Browse Source

实现导出分布式印刷数据包。

deason 7 years ago
parent
commit
5a766213e7
11 changed files with 2126 additions and 1499 deletions
  1. 57 56
      examcloud-core-questions-api-provider/src/main/java/cn/com/qmth/examcloud/service/core/api/ExportPaperController.java
  2. 226 235
      examcloud-core-questions-api-provider/src/main/java/cn/com/qmth/examcloud/service/core/api/ExtractConfigController.java
  3. 6 2
      examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/FileDisposeUtil.java
  4. 9 0
      examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/converter/model/platform/BlockVo.java
  5. 49 45
      examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/enums/ExamFileType.java
  6. 30 28
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/ExportPaperService.java
  7. 33 30
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/ExtractConfigFileService.java
  8. 145 0
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/converter/ConvertQuestion.java
  9. 473 0
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/converter/PrintExamPaperService.java
  10. 636 649
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/ExportPaperServiceImpl.java
  11. 462 454
      examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/ExtractConfigFileServiceImpl.java

+ 57 - 56
examcloud-core-questions-api-provider/src/main/java/cn/com/qmth/examcloud/service/core/api/ExportPaperController.java

@@ -1,12 +1,10 @@
 package cn.com.qmth.examcloud.service.core.api;
 
-import java.io.IOException;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
+import cn.com.qmth.examcloud.core.questions.dao.ExportServiceManageRepo;
+import cn.com.qmth.examcloud.core.questions.dao.entity.ExportServiceManage;
+import cn.com.qmth.examcloud.core.questions.service.ExportPaperService;
+import cn.com.qmth.examcloud.core.questions.service.export.SydxExportPaperService;
 import io.swagger.annotations.ApiOperation;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -15,13 +13,12 @@ import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 
-import cn.com.qmth.examcloud.core.questions.dao.ExportServiceManageRepo;
-import cn.com.qmth.examcloud.core.questions.dao.entity.ExportServiceManage;
-import cn.com.qmth.examcloud.core.questions.service.ExportPaperService;
-import cn.com.qmth.examcloud.core.questions.service.export.SydxExportPaperService;
-
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * Created by songyue on 17/3/30.
@@ -30,41 +27,45 @@ import javax.servlet.http.HttpServletResponse;
 @RequestMapping("${api_cqb}/")
 public class ExportPaperController {
     protected static final Logger log = LoggerFactory.getLogger(ExportPaperController.class);
-    
+
     @Autowired
     ExportServiceManageRepo exportServiceManageRepo;
-    
+
     @Autowired
     SydxExportPaperService sydxExportPaperService;
-    
+
     @Autowired
     private ExportPaperService exportPaperService;
+
     /**
      * 导出单个试卷
+     *
      * @param id
      * @return
      */
-    @ApiOperation(value="导出试卷",notes="导出试卷")
+    @ApiOperation(value = "导出试卷", notes = "导出试卷")
     @GetMapping(value = "/paper/export/{id}/{exportContentList}/{orgName}/{loginName}/{examType}")
     public void getPaperById(HttpServletRequest request, HttpServletResponse response,
-    						 @PathVariable String id,
-    						 @PathVariable String orgName,
-    						 @PathVariable String exportContentList,
-    						 @PathVariable String loginName,
-    						 @PathVariable String examType){
-    	log.info("导出开始");
-    	try {
-    		ExportServiceManage esm = exportServiceManageRepo.findByOrgName(orgName);
-    		exportPaperService.exportPaperFile(id,esm.getExportServiceName(),exportContentList,response,loginName,examType);
-		} catch (Exception e) {
-			e.printStackTrace();
-	        log.error("导出异常:"+e.getMessage());
-		}
-    	log.info("导出结束");
+                             @PathVariable String id,
+                             @PathVariable String orgName,
+                             @PathVariable String exportContentList,
+                             @PathVariable String loginName,
+                             @PathVariable String examType) {
+        log.info("导出开始");
+        try {
+            String psw = request.getParameter("psw");
+            ExportServiceManage esm = exportServiceManageRepo.findByOrgName(orgName);
+            exportPaperService.exportPaperFile(id, esm.getExportServiceName(), exportContentList, response, loginName, examType, psw);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("导出异常:" + e.getMessage());
+        }
+        log.info("导出结束");
     }
 
     /**
      * 批量导出试卷
+     *
      * @param request
      * @param response
      * @param paperIds
@@ -72,35 +73,35 @@ public class ExportPaperController {
      * @param exportContentList
      * @param loginName
      */
-    @ApiOperation(value="批量导出试卷", notes="批量导出")
+    @ApiOperation(value = "批量导出试卷", notes = "批量导出")
     @GetMapping(value = "/paper/batch_export/{paperIds}/{exportContentList}/{orgName}/{loginName}/{examType}")
-    public void getPaperByIds(HttpServletRequest request ,HttpServletResponse response,
-    						  @PathVariable String paperIds,
-    						  @PathVariable String orgName,
-    						  @PathVariable String exportContentList,
-    						  @PathVariable String loginName,
-    						  @PathVariable String examType){
-    	log.info("批量导出");
-    	List<String> paperList = Stream.of(paperIds.split(",")).collect(Collectors.toList());
-    	ExportServiceManage esm = exportServiceManageRepo.findByOrgName(orgName);
-    	try {
-			exportPaperService.exportPaperFiles(paperList,esm.getExportServiceName(),exportContentList, response, loginName,examType);
-		} catch (Exception e) {
-			e.printStackTrace();
-			log.error("导出异常:"+e.getMessage());
-		}
-    	log.info("导出结束");
+    public void getPaperByIds(HttpServletRequest request, HttpServletResponse response,
+                              @PathVariable String paperIds,
+                              @PathVariable String orgName,
+                              @PathVariable String exportContentList,
+                              @PathVariable String loginName,
+                              @PathVariable String examType) {
+        log.info("批量导出");
+        List<String> paperList = Stream.of(paperIds.split(",")).collect(Collectors.toList());
+        ExportServiceManage esm = exportServiceManageRepo.findByOrgName(orgName);
+        try {
+            exportPaperService.exportPaperFiles(paperList, esm.getExportServiceName(), exportContentList, response, loginName, examType);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("导出异常:" + e.getMessage());
+        }
+        log.info("导出结束");
     }
-    
-    @ApiOperation(value="导出试题分布数量", notes="导出试题分布数量")
+
+    @ApiOperation(value = "导出试题分布数量", notes = "导出试题分布数量")
     @GetMapping(value = "/paper/export/course/question/{courseNo}")
-    public void downQuestionDistribute(HttpServletResponse response,@PathVariable String courseNo){
-    	log.info("开始导出Excel");
-    	try {
-			exportPaperService.downQuestionDistribute(courseNo,response);
-		} catch (IOException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
+    public void downQuestionDistribute(HttpServletResponse response, @PathVariable String courseNo) {
+        log.info("开始导出Excel");
+        try {
+            exportPaperService.downQuestionDistribute(courseNo, response);
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
     }
 }

+ 226 - 235
examcloud-core-questions-api-provider/src/main/java/cn/com/qmth/examcloud/service/core/api/ExtractConfigController.java

@@ -1,16 +1,17 @@
 package cn.com.qmth.examcloud.service.core.api;
 
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
+import cn.com.qmth.examcloud.common.dto.question.PaperDto;
+import cn.com.qmth.examcloud.common.dto.question.QuestionDto;
+import cn.com.qmth.examcloud.commons.base.util.ErrorMsg;
+import cn.com.qmth.examcloud.commons.web.security.bean.User;
+import cn.com.qmth.examcloud.commons.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.core.questions.base.enums.ExportWay;
+import cn.com.qmth.examcloud.core.questions.dao.entity.ExtractConfig;
+import cn.com.qmth.examcloud.core.questions.service.ExtractConfigFileService;
+import cn.com.qmth.examcloud.core.questions.service.ExtractConfigService;
+import cn.com.qmth.examcloud.core.questions.service.bean.dto.ExportPaperInfoModel;
 import io.swagger.annotations.ApiOperation;
-
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -19,251 +20,241 @@ import org.springframework.data.domain.Page;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.*;
 
-import cn.com.qmth.examcloud.common.dto.question.PaperDto;
-import cn.com.qmth.examcloud.common.dto.question.QuestionDto;
-import cn.com.qmth.examcloud.commons.web.security.bean.User;
-import cn.com.qmth.examcloud.commons.web.security.entity.AccessUser;
-import cn.com.qmth.examcloud.commons.web.support.ControllerSupport;
-import cn.com.qmth.examcloud.commons.base.util.ErrorMsg;
-import cn.com.qmth.examcloud.core.questions.service.bean.dto.ExportPaperInfoModel;
-import cn.com.qmth.examcloud.core.questions.dao.entity.ExtractConfig;
-import cn.com.qmth.examcloud.core.questions.service.ExtractConfigFileService;
-import cn.com.qmth.examcloud.core.questions.service.ExtractConfigService;
-import cn.com.qmth.examcloud.core.questions.base.enums.ExportWay;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 
 /**
- * 
- * @author  	chenken
- * @date    	2017年4月14日 下午6:05:37
- * @company 	QMTH
+ * @author chenken
+ * @date 2017年4月14日 下午6:05:37
+ * @company QMTH
  * @description 调卷规则控制器
  */
 @Controller
 @RequestMapping("${api_cqb}/")
 public class ExtractConfigController extends ControllerSupport {
-	private static final Logger logger = LoggerFactory.getLogger(ExtractConfigController.class);
-	
-	@Autowired
-	private ExtractConfigService extractConfigService;
-	
-	@Autowired
-	private ExtractConfigFileService extractConfigFileService;
-	
-	@ApiOperation(value = "根据考试ID和课程ID获取调卷规则", notes = "根据考试ID和课程ID获取调卷规则")
+    private static final Logger logger = LoggerFactory.getLogger(ExtractConfigController.class);
+
+    @Autowired
+    private ExtractConfigService extractConfigService;
+
+    @Autowired
+    private ExtractConfigFileService extractConfigFileService;
+
+    @ApiOperation(value = "根据考试ID和课程ID获取调卷规则", notes = "根据考试ID和课程ID获取调卷规则")
     @GetMapping(value = "/findPageExtractConfig/{currentPage}/{pageSize}")
-	public ResponseEntity findPageExtractConfig(@PathVariable int currentPage,
-														       @PathVariable int pageSize,
-															   @RequestParam("examId") Long examId,
-															   @RequestParam("courseNo") String courseNo,
-															   @RequestParam("courseLevel") String courseLevel){
-		try{
-			Page<ExtractConfig> extractConfigPageList = extractConfigService.findPageExtractConfig(currentPage,pageSize,examId,courseNo,courseLevel);
-			return new ResponseEntity<Page<ExtractConfig>>(extractConfigPageList,HttpStatus.OK);
-		}catch(Exception e){
-			e.printStackTrace();
-			return new ResponseEntity<Object>(new ErrorMsg(e.getMessage()),HttpStatus.INTERNAL_SERVER_ERROR);
-		}
-	}
-	
-	@ApiOperation(value = "根据考试ID和课程ID获取调卷规则", notes = "根据考试ID和课程ID获取调卷规则")
+    public ResponseEntity findPageExtractConfig(@PathVariable int currentPage,
+                                                @PathVariable int pageSize,
+                                                @RequestParam("examId") Long examId,
+                                                @RequestParam("courseNo") String courseNo,
+                                                @RequestParam("courseLevel") String courseLevel) {
+        try {
+            Page<ExtractConfig> extractConfigPageList = extractConfigService.findPageExtractConfig(currentPage, pageSize, examId, courseNo, courseLevel);
+            return new ResponseEntity<Page<ExtractConfig>>(extractConfigPageList, HttpStatus.OK);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return new ResponseEntity<Object>(new ErrorMsg(e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    @ApiOperation(value = "根据考试ID和课程ID获取调卷规则", notes = "根据考试ID和课程ID获取调卷规则")
     @GetMapping(value = "/extractConfig/{examId}/{courseCode}")
-	public ResponseEntity<ExtractConfig> findExtractConfig(@PathVariable Long examId,@PathVariable String courseCode){
-		ExtractConfig condition = new ExtractConfig();
-		condition.setExamId(examId);
-		condition.setCourseCode(courseCode);
-		ExtractConfig extractConfig = extractConfigService.findConfig(condition);
-		return new ResponseEntity<ExtractConfig>(extractConfig,HttpStatus.OK);
-	}
-	
-	@ApiOperation(value = "根据ID获取调卷规则", notes = "根据ID获取调卷规则")
+    public ResponseEntity<ExtractConfig> findExtractConfig(@PathVariable Long examId, @PathVariable String courseCode) {
+        ExtractConfig condition = new ExtractConfig();
+        condition.setExamId(examId);
+        condition.setCourseCode(courseCode);
+        ExtractConfig extractConfig = extractConfigService.findConfig(condition);
+        return new ResponseEntity<ExtractConfig>(extractConfig, HttpStatus.OK);
+    }
+
+    @ApiOperation(value = "根据ID获取调卷规则", notes = "根据ID获取调卷规则")
     @GetMapping(value = "/extractConfig/{id}")
-	public ResponseEntity<ExtractConfig> findExtractConfigById(@PathVariable String id){
-		ExtractConfig extractConfig = extractConfigService.findConfigById(id);
-		return new ResponseEntity<ExtractConfig>(extractConfig,HttpStatus.OK);
-	} 
-	
-	@ApiOperation(value = "保存调卷规则", notes = "保存调卷规则")
+    public ResponseEntity<ExtractConfig> findExtractConfigById(@PathVariable String id) {
+        ExtractConfig extractConfig = extractConfigService.findConfigById(id);
+        return new ResponseEntity<ExtractConfig>(extractConfig, HttpStatus.OK);
+    }
+
+    @ApiOperation(value = "保存调卷规则", notes = "保存调卷规则")
     @PutMapping(value = "/extractConfig/{isbuildFile}")
-	public ResponseEntity<Object> saveExtractConfig(HttpServletRequest request,@PathVariable Integer isbuildFile,@RequestBody ExtractConfig extractConfig){
-		try{
-			User user = getAccessUser();
-			//AccessUser accessUser = (AccessUser) request.getAttribute("accessUser");
-			extractConfig.setOrgId(user.getRootOrgId()+"");
-			extractConfig.setOrgName(user.getRootOrgName());
-			extractConfigFileService.saveExtractConfigAndBuildPaperFile(extractConfig,isbuildFile,user);
-			return new ResponseEntity<Object>(HttpStatus.OK);
-		}catch(Exception e){
-			e.printStackTrace();
-			return new ResponseEntity<Object>(new ErrorMsg(e.getMessage()),HttpStatus.INTERNAL_SERVER_ERROR);
-		}
-	}
-	
-	@ApiOperation(value = "抽取考试试卷", notes = "抽取考试试卷")
+    public ResponseEntity<Object> saveExtractConfig(HttpServletRequest request, @PathVariable Integer isbuildFile, @RequestBody ExtractConfig extractConfig) {
+        try {
+            User user = getAccessUser();
+            //AccessUser accessUser = (AccessUser) request.getAttribute("accessUser");
+            extractConfig.setOrgId(user.getRootOrgId() + "");
+            extractConfig.setOrgName(user.getRootOrgName());
+            extractConfigFileService.saveExtractConfigAndBuildPaperFile(extractConfig, isbuildFile, user);
+            return new ResponseEntity<Object>(HttpStatus.OK);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return new ResponseEntity<Object>(new ErrorMsg(e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    @ApiOperation(value = "抽取考试试卷", notes = "抽取考试试卷")
     @GetMapping(value = "/extract/{exam_id}/{course_code}/{group_code}")
-    public ResponseEntity extract(@PathVariable Long exam_id, @PathVariable String course_code,@PathVariable String group_code) {
-		try{
-			Map<String, Object> returnMap = extractConfigService.extractExamPaper(exam_id, course_code, group_code);
-			if(returnMap.get("errorMsg")==null){
-				PaperDto paperDto = (PaperDto) returnMap.get("paperDto");
-				return new ResponseEntity<PaperDto>(paperDto, HttpStatus.OK);
-			}else{
-				return new ResponseEntity<String>(returnMap.get("errorMsg")+"", HttpStatus.OK);
-			}
-		}catch(Exception e){
-			logger.error("抽卷失败",e);
-			return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
-		}
-	}
-	
-	@ApiOperation(value = "抽取单个试题", notes = "抽取单个试题")
+    public ResponseEntity extract(@PathVariable Long exam_id, @PathVariable String course_code, @PathVariable String group_code) {
+        try {
+            Map<String, Object> returnMap = extractConfigService.extractExamPaper(exam_id, course_code, group_code);
+            if (returnMap.get("errorMsg") == null) {
+                PaperDto paperDto = (PaperDto) returnMap.get("paperDto");
+                return new ResponseEntity<PaperDto>(paperDto, HttpStatus.OK);
+            } else {
+                return new ResponseEntity<String>(returnMap.get("errorMsg") + "", HttpStatus.OK);
+            }
+        } catch (Exception e) {
+            logger.error("抽卷失败", e);
+            return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    @ApiOperation(value = "抽取单个试题", notes = "抽取单个试题")
     @GetMapping(value = "/extractQues/{examId}/{courseCode}/{groupCode}/{paperDetailUnitId}")
     public ResponseEntity<Object> extractQuestion(@PathVariable String examId,
-    											  @PathVariable String courseCode,
-    											  @PathVariable String groupCode,
-    											  @PathVariable String paperDetailUnitId){
-		try{
-	        QuestionDto questionDto = extractConfigService.extractExamQuestion(examId,courseCode,groupCode,paperDetailUnitId);
-	        return new ResponseEntity<Object>(questionDto,HttpStatus.OK);
-		}catch(Exception e){
-			logger.error("抽题失败",e);
-			e.printStackTrace();
-			return new ResponseEntity<Object>("抽题失败:"+e.getMessage(),HttpStatus.INTERNAL_SERVER_ERROR);
-		}
-        
+                                                  @PathVariable String courseCode,
+                                                  @PathVariable String groupCode,
+                                                  @PathVariable String paperDetailUnitId) {
+        try {
+            QuestionDto questionDto = extractConfigService.extractExamQuestion(examId, courseCode, groupCode, paperDetailUnitId);
+            return new ResponseEntity<Object>(questionDto, HttpStatus.OK);
+        } catch (Exception e) {
+            logger.error("抽题失败", e);
+            e.printStackTrace();
+            return new ResponseEntity<Object>("抽题失败:" + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+
     }
-	
-	@ApiOperation(value = "判断试卷中的题是否都为客观题(单选、多选、判断),包括套题中的小题", 
-				  notes = "判断试卷中的题是否都为客观题(单选、多选、判断),包括套题中的小题")
+
+    @ApiOperation(value = "判断试卷中的题是否都为客观题(单选、多选、判断),包括套题中的小题",
+            notes = "判断试卷中的题是否都为客观题(单选、多选、判断),包括套题中的小题")
     @GetMapping(value = "/checkObjective/{paperId}")
-	public ResponseEntity<Map<String, Object>> checkIsAllObjectiveQuestion(@PathVariable String paperId){
-		Map<String, Object> quesMap = new HashMap<String, Object>();
-		try{
-			if(StringUtils.isBlank(paperId)){
-				quesMap.put("message","paperId不能为空");
-				return new ResponseEntity<Map<String, Object>>(HttpStatus.INTERNAL_SERVER_ERROR);
-			}
-			boolean result = extractConfigService.checkIsAllQbjectiveQuestion(paperId);
-			quesMap.put("result", result);
-			quesMap.put("message", result?"全为客观题":"不全为客观题");
-			return new ResponseEntity<Map<String, Object>>(quesMap, HttpStatus.OK);
-		}catch(Exception e){
-			logger.error("调用checkIsAllQbjectiveQuestion失败",e);
-			quesMap.put("result","error");
-			quesMap.put("message","调用失败");
-			return new ResponseEntity<Map<String, Object>>(HttpStatus.INTERNAL_SERVER_ERROR);
-		}
-	}
-	
-	@ApiOperation(value = "导出单张考试试卷、答案、试卷结构", notes = "导出单张考试试卷、答案、试卷结构")
-	@GetMapping(value = "/exportSingleExamPaperInfo/{orgName}/{exportWay}/{examId}/{courseId}/{exportContentList}/{loginName}")
-	public void exportSingleExamPaperInfo(HttpServletResponse response,
-											@PathVariable String exportWay,
-											@PathVariable String orgName,
-											@PathVariable String examId,
-											@PathVariable String courseId,
-											@PathVariable String exportContentList,
-											@PathVariable String loginName){
-		ExportPaperInfoModel exportModel = new ExportPaperInfoModel();
-		exportModel.setExportWay(ExportWay.strToEnum(exportWay));
-		exportModel.setExamId(examId);
-		exportModel.setCourseId(courseId);
-		String[] exportContentArray = exportContentList.split(",");
-		List<String> list = new ArrayList<String>();
-		for(int i = 0;i<exportContentArray.length;i++){
-			list.add(exportContentArray[i]);
-		}
-		exportModel.setExportContentList(list);
-		try {
-			extractConfigFileService.exportExamPaperInfo(exportModel,response,loginName,orgName);
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-	}
-	
-	@ApiOperation(value = "导出试卷文件前校验", notes = "导出试卷文件前校验")
-	@GetMapping(value = "/exportBatchExamPaperInfoCheck/{exportWay}/{examId}")
-	public ResponseEntity<Object> exportExamPaperInfoCheck(HttpServletResponse response,
-											@PathVariable String exportWay,
-											@PathVariable String examId){
-		ExportPaperInfoModel exportModel = new ExportPaperInfoModel();
-		exportModel.setExportWay(ExportWay.strToEnum(exportWay));
-		exportModel.setExamId(examId);
-		try {
-			extractConfigFileService.exportExamPaperInfoCheck(exportModel,response);
-			return new ResponseEntity<Object>(HttpStatus.OK);
-		} catch (Exception e) {
-			e.printStackTrace();
-			return new ResponseEntity<Object>(new ErrorMsg(e.getMessage()),HttpStatus.OK);
-		}
-	}
-	
-	
-	@ApiOperation(value = "导出整个考试下所有 课程的试卷、答案、试卷结构", notes = "导出整个考试下所有 课程的试卷、答案、试卷结构")
-	@GetMapping(value = "/exportBatchExamPaperInfo/{orgName}/{exportWay}/{examId}/{exportContentList}/{loginName}")
-	public void exportBatchExamPaperInfo(HttpServletResponse response,
-											@PathVariable String exportWay,
-											@PathVariable String orgName,
-											@PathVariable String examId,
-											@PathVariable String exportContentList,
-											@PathVariable String loginName){
-		ExportPaperInfoModel exportModel = new ExportPaperInfoModel();
-		exportModel.setExportWay(ExportWay.strToEnum(exportWay));
-		exportModel.setExamId(examId);
-		String[] exportContentArray = exportContentList.split(",");
-		List<String> list = new ArrayList<String>();
-		for(int i = 0;i<exportContentArray.length;i++){
-			list.add(exportContentArray[i]);
-		}
-		exportModel.setExportContentList(list);
-		try {
-			extractConfigFileService.exportExamPaperInfo(exportModel,response,loginName,orgName);
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-	}
-	
-	@ApiOperation(value = "根据试卷id抽取考试试卷", notes = "根据试卷id抽取考试试卷")
+    public ResponseEntity<Map<String, Object>> checkIsAllObjectiveQuestion(@PathVariable String paperId) {
+        Map<String, Object> quesMap = new HashMap<String, Object>();
+        try {
+            if (StringUtils.isBlank(paperId)) {
+                quesMap.put("message", "paperId不能为空");
+                return new ResponseEntity<Map<String, Object>>(HttpStatus.INTERNAL_SERVER_ERROR);
+            }
+            boolean result = extractConfigService.checkIsAllQbjectiveQuestion(paperId);
+            quesMap.put("result", result);
+            quesMap.put("message", result ? "全为客观题" : "不全为客观题");
+            return new ResponseEntity<Map<String, Object>>(quesMap, HttpStatus.OK);
+        } catch (Exception e) {
+            logger.error("调用checkIsAllQbjectiveQuestion失败", e);
+            quesMap.put("result", "error");
+            quesMap.put("message", "调用失败");
+            return new ResponseEntity<Map<String, Object>>(HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    @ApiOperation(value = "导出单张考试试卷、答案、试卷结构", notes = "导出单张考试试卷、答案、试卷结构")
+    @GetMapping(value = "/exportSingleExamPaperInfo/{orgName}/{exportWay}/{examId}/{courseId}/{exportContentList}/{loginName}")
+    public void exportSingleExamPaperInfo(HttpServletResponse response,
+                                          @PathVariable String exportWay,
+                                          @PathVariable String orgName,
+                                          @PathVariable String examId,
+                                          @PathVariable String courseId,
+                                          @PathVariable String exportContentList,
+                                          @PathVariable String loginName,
+                                          @RequestParam(required = false) String psw) {
+        ExportPaperInfoModel exportModel = new ExportPaperInfoModel();
+        exportModel.setExportWay(ExportWay.strToEnum(exportWay));
+        exportModel.setExamId(examId);
+        exportModel.setCourseId(courseId);
+        String[] exportContentArray = exportContentList.split(",");
+        List<String> list = new ArrayList<String>();
+        for (int i = 0; i < exportContentArray.length; i++) {
+            list.add(exportContentArray[i]);
+        }
+        exportModel.setExportContentList(list);
+        try {
+            extractConfigFileService.exportExamPaperInfo(exportModel, response, loginName, orgName, psw);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @ApiOperation(value = "导出试卷文件前校验", notes = "导出试卷文件前校验")
+    @GetMapping(value = "/exportBatchExamPaperInfoCheck/{exportWay}/{examId}")
+    public ResponseEntity<Object> exportExamPaperInfoCheck(HttpServletResponse response,
+                                                           @PathVariable String exportWay,
+                                                           @PathVariable String examId) {
+        ExportPaperInfoModel exportModel = new ExportPaperInfoModel();
+        exportModel.setExportWay(ExportWay.strToEnum(exportWay));
+        exportModel.setExamId(examId);
+        try {
+            extractConfigFileService.exportExamPaperInfoCheck(exportModel, response);
+            return new ResponseEntity<Object>(HttpStatus.OK);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return new ResponseEntity<Object>(new ErrorMsg(e.getMessage()), HttpStatus.OK);
+        }
+    }
+
+
+    @ApiOperation(value = "导出整个考试下所有 课程的试卷、答案、试卷结构", notes = "导出整个考试下所有 课程的试卷、答案、试卷结构")
+    @GetMapping(value = "/exportBatchExamPaperInfo/{orgName}/{exportWay}/{examId}/{exportContentList}/{loginName}")
+    public void exportBatchExamPaperInfo(HttpServletResponse response,
+                                         @PathVariable String exportWay,
+                                         @PathVariable String orgName,
+                                         @PathVariable String examId,
+                                         @PathVariable String exportContentList,
+                                         @PathVariable String loginName) {
+        ExportPaperInfoModel exportModel = new ExportPaperInfoModel();
+        exportModel.setExportWay(ExportWay.strToEnum(exportWay));
+        exportModel.setExamId(examId);
+        String[] exportContentArray = exportContentList.split(",");
+        List<String> list = new ArrayList<String>();
+        for (int i = 0; i < exportContentArray.length; i++) {
+            list.add(exportContentArray[i]);
+        }
+        exportModel.setExportContentList(list);
+        try {
+            extractConfigFileService.exportExamPaperInfo(exportModel, response, loginName, orgName, null);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @ApiOperation(value = "根据试卷id抽取考试试卷", notes = "根据试卷id抽取考试试卷")
     @GetMapping(value = "/extract/paper/{paperId}")
     public ResponseEntity<Object> extractPaper(@PathVariable String paperId) {
-		try{
-			Map<String, Object> returnMap = extractConfigService.extractPaper(paperId);
-			if(returnMap.get("errorMsg")==null){
-				PaperDto paperDto = (PaperDto) returnMap.get("paperDto");
-				return new ResponseEntity<Object>(paperDto, HttpStatus.OK);
-			}else{
-				return new ResponseEntity<Object>(returnMap.get("errorMsg")+"", HttpStatus.OK);
-			}
-		}catch(Exception e){
-			logger.error("抽卷失败",e);
-			return new ResponseEntity<Object>(HttpStatus.INTERNAL_SERVER_ERROR);
-		}
-	}
+        try {
+            Map<String, Object> returnMap = extractConfigService.extractPaper(paperId);
+            if (returnMap.get("errorMsg") == null) {
+                PaperDto paperDto = (PaperDto) returnMap.get("paperDto");
+                return new ResponseEntity<Object>(paperDto, HttpStatus.OK);
+            } else {
+                return new ResponseEntity<Object>(returnMap.get("errorMsg") + "", HttpStatus.OK);
+            }
+        } catch (Exception e) {
+            logger.error("抽卷失败", e);
+            return new ResponseEntity<Object>(HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    @ApiOperation(value = "测试获取试卷Dto", notes = "测试获取试卷Dto")
+    @GetMapping(value = "/extract/getPaperDto/{paperId}")
+    public ResponseEntity getPaperDto(@PathVariable String paperId) {
+        try {
+            PaperDto paperDto = extractConfigService.getPaperDtoByPaperNew(paperId);
+            return new ResponseEntity<Object>(paperDto, HttpStatus.OK);
+        } catch (Exception e) {
+            logger.error("获取试卷Dto失败", e);
+            return new ResponseEntity<Object>(HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    @ApiOperation(value = "通过试卷id得到答案", notes = "通过试卷id得到答案")
+    @GetMapping(value = "/extract/getAnswerHtml/{paperId}")
+    public ResponseEntity<Object> getAnswerHtml(@PathVariable String paperId) {
+        String answerHtml = extractConfigService.getAnswerHtml(paperId);
+        return new ResponseEntity<Object>(answerHtml, HttpStatus.OK);
+    }
 
-	@ApiOperation(value = "测试获取试卷Dto", notes = "测试获取试卷Dto")
-	@GetMapping(value = "/extract/getPaperDto/{paperId}")
-	public ResponseEntity getPaperDto(@PathVariable String paperId) {
-		try{
-			PaperDto paperDto = extractConfigService.getPaperDtoByPaperNew(paperId);
-			return new ResponseEntity<Object>(paperDto, HttpStatus.OK);
-		}catch(Exception e){
-			logger.error("获取试卷Dto失败",e);
-			return new ResponseEntity<Object>(HttpStatus.INTERNAL_SERVER_ERROR);
-		}
-	}
-	
-	@ApiOperation(value="通过试卷id得到答案", notes="通过试卷id得到答案")
-	@GetMapping(value="/extract/getAnswerHtml/{paperId}")
-	public ResponseEntity<Object> getAnswerHtml(@PathVariable String paperId){
-		String answerHtml = extractConfigService.getAnswerHtml(paperId);
-		return new ResponseEntity<Object>(answerHtml,HttpStatus.OK);
-	}
-	
 }	

+ 6 - 2
examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/FileDisposeUtil.java

@@ -200,14 +200,18 @@ public class FileDisposeUtil {
 						zos = new ZipOutputStream(new BufferedOutputStream(fos));
 						byte[] bufs = new byte[1024 * 10];
 						for (int i = 0; i < sourceFiles.length; i++) {
+							File file=sourceFiles[i];
+							if(!file.isFile()){
+								continue;
+							}
 							try{
 								//创建ZIP实体,并添加进压缩包
 								String fileEncode = System.getProperty("file.encoding");
-								String name = new String(sourceFiles[i].getName().getBytes(fileEncode),"UTF-8");
+								String name = new String(file.getName().getBytes(fileEncode),"UTF-8");
 								ZipEntry zipEntry = new ZipEntry(name);
 								zos.putNextEntry(zipEntry);
 								//读取待压缩的文件并写进压缩包里
-								fis = new FileInputStream(sourceFiles[i]);
+								fis = new FileInputStream(file);
 								bis = new BufferedInputStream(fis, 1024 * 10);
 								int read = 0;
 								while ((read = bis.read(bufs, 0, 1024 * 10)) != -1) {

+ 9 - 0
examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/converter/model/platform/BlockVo.java

@@ -16,6 +16,7 @@ public class BlockVo implements Serializable {
     private static final long serialVersionUID = 2180336388838138300L;
     private String type;//模块类型
     private String value;//模块内容
+    private Integer playTime;//播放次数
     private ParamVo param;//附属参数
 
     public String getType() {
@@ -34,6 +35,14 @@ public class BlockVo implements Serializable {
         this.value = value;
     }
 
+    public Integer getPlayTime() {
+        return playTime;
+    }
+
+    public void setPlayTime(Integer playTime) {
+        this.playTime = playTime;
+    }
+
     public ParamVo getParam() {
         return param;
     }

+ 49 - 45
examcloud-core-questions-base/src/main/java/cn/com/qmth/examcloud/core/questions/base/enums/ExamFileType.java

@@ -1,53 +1,57 @@
 package cn.com.qmth.examcloud.core.questions.base.enums;
+
 /**
- * @author  	chenken
- * @date    	2017年7月13日 下午4:34:29
- * @company 	QMTH
+ * @author chenken
+ * @date 2017年7月13日 下午4:34:29
+ * @company QMTH
  * @description 考试 文件类型
  */
 public enum ExamFileType {
-	/**
-	 * 试卷
-	 */
-	PAPER("试卷"),
-	/**
-	 * 答案
-	 */
-	ANSWER("答案"),
-	/**
-	 * ZIP文件
-	 * 试卷结构
-	 * 主观题
-	 */
-	PAPER_STRUCTURE_SUBJECTIVE("主观题"),
-	/**
-	 * ZIP文件
-	 * 试卷结构
-	 * 客观题
-	 */
-	PAPER_STRUCTURE_OBJECTIVE("客观题"),
-	/**
-	 * 音频文件
-	 */
-	AUDIO("音频文件"),
-	/**
-	 * 机考数据包
-	 */
-	COMPUTERTEST_PACKAGE("机考数据包");
-	
-	private String name;
-	
-	private ExamFileType(String name){
-		this.name = name;
-	}
+    /**
+     * 试卷
+     */
+    PAPER("试卷"),
+    /**
+     * 答案
+     */
+    ANSWER("答案"),
+    /**
+     * ZIP文件
+     * 试卷结构
+     * 主观题
+     */
+    PAPER_STRUCTURE_SUBJECTIVE("主观题"),
+    /**
+     * ZIP文件
+     * 试卷结构
+     * 客观题
+     */
+    PAPER_STRUCTURE_OBJECTIVE("客观题"),
+    /**
+     * 音频文件
+     */
+    AUDIO("音频文件"),
+    /**
+     * 机考数据包
+     */
+    COMPUTERTEST_PACKAGE("机考数据包"),
+    /**
+     * 分布式印刷数据包
+     */
+    PRINT_EXAM_PACKAGE("分布式印刷数据包");
+
+    private String name;
+
+    private ExamFileType(String name) {
+        this.name = name;
+    }
 
-	public String getName() {
-		return name;
-	}
+    public String getName() {
+        return name;
+    }
 
-	public void setName(String name) {
-		this.name = name;
-	}
-	
-}
+    public void setName(String name) {
+        this.name = name;
+    }
 
+}

+ 30 - 28
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/ExportPaperService.java

@@ -1,38 +1,40 @@
 package cn.com.qmth.examcloud.core.questions.service;
 
+import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.List;
 
-import javax.servlet.http.HttpServletResponse;
-
 public interface ExportPaperService {
 
-	/**
-	 * 导出单个试卷,答案,机考数据包
-	 * @param examId
-	 * @param courseNo
-	 * @param paperType
-	 * @param response
-	 * @param exportContentList
-	 * @throws Exception
-	 */
-	public void exportPaperFile(String paperId,String serviceName,String exportContentList,HttpServletResponse response, String loginName, String examType)  throws Exception;
+    /**
+     * 导出单个试卷,答案,机考数据包
+     *
+     * @param examId
+     * @param courseNo
+     * @param paperType
+     * @param response
+     * @param exportContentList
+     * @throws Exception
+     */
+    public void exportPaperFile(String paperId, String serviceName, String exportContentList, HttpServletResponse response, String loginName, String examType, String psw) throws Exception;
 
-	/**
-	 * 批量导出试卷,答案,机考数据包
-	 * @param paperIds
-	 * @param serviceName
-	 * @param exportContentList
-	 * @param response
-	 * @param loginName
-	 * @throws Exception
-	 */
-	public void exportPaperFiles(List<String> paperList,String serviceName,String exportContentList,HttpServletResponse response, String loginName, String examType)  throws Exception;
+    /**
+     * 批量导出试卷,答案,机考数据包
+     *
+     * @param paperIds
+     * @param serviceName
+     * @param exportContentList
+     * @param response
+     * @param loginName
+     * @throws Exception
+     */
+    public void exportPaperFiles(List<String> paperList, String serviceName, String exportContentList, HttpServletResponse response, String loginName, String examType) throws Exception;
 
-	/**
-	 * 导出课程下的试题分布Excel
-	 * @param courseNo
-	 * @param response
-	 */
-	public void downQuestionDistribute(String courseNo,HttpServletResponse response) throws IOException;
+    /**
+     * 导出课程下的试题分布Excel
+     *
+     * @param courseNo
+     * @param response
+     */
+    public void downQuestionDistribute(String courseNo, HttpServletResponse response) throws IOException;
 }

+ 33 - 30
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/ExtractConfigFileService.java

@@ -1,40 +1,43 @@
 package cn.com.qmth.examcloud.core.questions.service;
 
-import javax.servlet.http.HttpServletResponse;
-
 import cn.com.qmth.examcloud.commons.web.security.bean.User;
-import cn.com.qmth.examcloud.commons.web.security.entity.AccessUser;
-import cn.com.qmth.examcloud.core.questions.service.bean.dto.ExportPaperInfoModel;
 import cn.com.qmth.examcloud.core.questions.dao.entity.ExtractConfig;
+import cn.com.qmth.examcloud.core.questions.service.bean.dto.ExportPaperInfoModel;
+
+import javax.servlet.http.HttpServletResponse;
 
 /**
- * @author  	chenken
- * @date    	2017年7月31日 下午6:03:26
- * @company 	QMTH
+ * @author chenken
+ * @date 2017年7月31日 下午6:03:26
+ * @company QMTH
  * @description 调卷规则--文件处理service
  */
 public interface ExtractConfigFileService {
-	
-	/**
-	 * 保存调卷规则,生成试卷文件
-	 * @param extractConfig
-	 * @param isbuildFile	1:生成试卷文件 0:不生成试卷文件
-	 * @param accessUser
-	 * @throws Exception
-	 */
-	public void saveExtractConfigAndBuildPaperFile(ExtractConfig extractConfig,Integer isbuildFile,User user) throws Exception;
-	
-	/**
-	 * 导出考试下的试卷信息  校验
-	 * @param exportModel
-	 * @param response
-	 * @throws Exception
-	 */
-	public void exportExamPaperInfoCheck(ExportPaperInfoModel exportModel,HttpServletResponse response) throws Exception ;
-	/**
-	 * 导出考试下的试卷信息
-	 * @param exportModel
-	 */
-	public void exportExamPaperInfo(ExportPaperInfoModel exportModel,HttpServletResponse response,String loginName,String orgName)  throws Exception ;
-}
 
+    /**
+     * 保存调卷规则,生成试卷文件
+     *
+     * @param extractConfig
+     * @param isbuildFile   1:生成试卷文件 0:不生成试卷文件
+     * @param accessUser
+     * @throws Exception
+     */
+    public void saveExtractConfigAndBuildPaperFile(ExtractConfig extractConfig, Integer isbuildFile, User user) throws Exception;
+
+    /**
+     * 导出考试下的试卷信息  校验
+     *
+     * @param exportModel
+     * @param response
+     * @throws Exception
+     */
+    public void exportExamPaperInfoCheck(ExportPaperInfoModel exportModel, HttpServletResponse response) throws Exception;
+
+    /**
+     * 导出考试下的试卷信息
+     *
+     * @param exportModel
+     */
+    public void exportExamPaperInfo(ExportPaperInfoModel exportModel, HttpServletResponse response, String loginName, String orgName, String psw) throws Exception;
+
+}

+ 145 - 0
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/converter/ConvertQuestion.java

@@ -0,0 +1,145 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-07-13 13:37:43.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.questions.service.converter;
+
+import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
+import cn.com.qmth.examcloud.core.questions.base.converter.model.platform.*;
+import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
+import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ConvertQuestion {
+
+    public static BodyVo parseBody(String bodyStr) {
+        BodyVo body = new BodyVo();
+        if (StringUtils.isBlank(bodyStr)) {
+            return body;
+        }
+        List<SectionVo> sections = splitSections(bodyStr);
+        body.setSections(sections);
+        return body;
+    }
+
+    public static AnswerVo parseAnswer(String answerStr) {
+        AnswerVo answer = new AnswerVo();
+        if (StringUtils.isBlank(answerStr)) {
+            return answer;
+        }
+        List<SectionVo> sections = splitSections(answerStr);
+        answer.setSections(sections);
+        return answer;
+    }
+
+    public static List<OptionVo> parseOption(Question question) {
+        List<OptionVo> options = new ArrayList<>();
+        List<QuesOption> oldOptions = question.getQuesOptions();
+        if (oldOptions == null || oldOptions.size() == 0) {
+            return options;
+        }
+        for (QuesOption oldOption : oldOptions) {
+            OptionVo option = new OptionVo();
+            option.setNumber(Integer.valueOf(oldOption.getNumber()));
+            option.setCorrect(oldOption.getIsCorrect() == 1 ? true : false);
+            BodyVo body = new BodyVo();
+            List<SectionVo> sections = splitSections(oldOption.getOptionBody());
+            body.setSections(sections);
+            option.setBody(body);
+            options.add(option);
+        }
+        return options;
+    }
+
+    private static List<SectionVo> splitSections(String str) {
+        List<SectionVo> sections = new ArrayList<>();
+        String[] rows = str.split("</p>");
+        for (String row : rows) {
+            List<BlockVo> blocks = splitBlocks(row);
+            if (blocks == null || blocks.size() == 0) {
+                continue;
+            }
+            SectionVo section = new SectionVo();
+            section.setBlocks(blocks);
+            sections.add(section);
+        }
+        return sections;
+    }
+
+    public static List<BlockVo> splitBlocks(String row) {
+        //去掉每行里面的<p>,<span>,</span>标签
+        row = row.replaceAll("<p>", "").replaceAll("</p>", "")
+                .replaceAll("<span>", "").replaceAll("</span>", "")
+                .replaceAll("</a>", "");
+        List<BlockVo> blocks = new ArrayList<>();
+        String[] strList = row.split("<|/>|>");
+        for (String str : strList) {
+            BlockVo block = new BlockVo();
+            if (str.startsWith("img")) {
+                //处理图片
+                block.setType("image");
+                str = "<" + str + ">";
+                ParamVo param = new ParamVo();
+                //获取图片的路径
+                List<String> srcList = splitImgInfo(str, "src");
+                if (srcList.size() > 0) {
+                    String src = srcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
+                    block.setValue(src);
+                }
+                //获取图片的宽度
+                List<String> widthList = splitImgInfo(str, "width");
+                if (widthList.size() > 0) {
+                    String width = widthList.get(0).replaceAll("width=\"", "").replaceAll("\"", "");
+                    param.setWidth(width);
+                }
+                //获取图片的高度
+                List<String> heightList = splitImgInfo(str, "height");
+                if (heightList.size() > 0) {
+                    String height = heightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
+                    param.setHeight(height);
+                }
+                block.setParam(param);
+                blocks.add(block);
+            } else if (str.startsWith("a") && str.contains("id") && str.contains("name")) {
+                //处理音频
+                block.setType("audio");
+                block.setPlayTime(1);
+                str = "<" + str + ">";
+                block.setValue(CommonUtils.getAttrValue(str, "id"));
+                blocks.add(block);
+            } else {
+                block.setType("text");
+                str = str.replace("&nbsp;", "");//消除空格
+                str = str.replace("&quot;", "\"");//将&quot;转换成\"
+                str = str.replace("&lt;", "<");//将&lt;转换成<
+                str = str.replace("&gt;", ">");//将&gt;转换成>
+                str = str.replace("&amp;", "&");//将&amp;转换成&
+                if (StringUtils.isNotBlank(str)) {
+                    block.setValue(str);
+                    blocks.add(block);
+                }
+            }
+        }
+        return blocks;
+    }
+
+    public static List<String> splitImgInfo(String str, String attr) {
+        String regex = attr + "=\"(.*?)\"";
+        Pattern p = Pattern.compile(regex, Pattern.DOTALL);
+        Matcher m = p.matcher(str);
+        List<String> list = new ArrayList<>();
+        while (m.find()) {
+            list.add(m.group());
+        }
+        return list;
+    }
+
+}

+ 473 - 0
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/converter/PrintExamPaperService.java

@@ -0,0 +1,473 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-07-12 15:33:35.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.core.questions.service.converter;
+
+import cn.com.qmth.examcloud.core.questions.base.converter.model.Constants;
+import cn.com.qmth.examcloud.core.questions.base.converter.model.PolicyType;
+import cn.com.qmth.examcloud.core.questions.base.converter.model.QuesStructType;
+import cn.com.qmth.examcloud.core.questions.base.converter.model.dps.*;
+import cn.com.qmth.examcloud.core.questions.base.converter.model.platform.PaperDetailVo;
+import cn.com.qmth.examcloud.core.questions.base.converter.model.platform.PaperVo;
+import cn.com.qmth.examcloud.core.questions.base.converter.model.platform.QuestionVo;
+import cn.com.qmth.examcloud.core.questions.base.converter.utils.Cryptogram;
+import cn.com.qmth.examcloud.core.questions.base.converter.utils.FileUtil;
+import cn.com.qmth.examcloud.core.questions.base.converter.utils.JsonMapper;
+import cn.com.qmth.examcloud.core.questions.base.converter.utils.NumUtil;
+import cn.com.qmth.examcloud.core.questions.base.enums.ExamFileType;
+import cn.com.qmth.examcloud.core.questions.dao.entity.Paper;
+import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetail;
+import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetailUnit;
+import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
+import cn.com.qmth.examcloud.core.questions.service.PaperDetailService;
+import cn.com.qmth.examcloud.core.questions.service.PaperService;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * 分布式印刷考试的试卷转换服务类
+ */
+@Service
+public class PrintExamPaperService {
+    private static Logger log = LoggerFactory.getLogger(PrintExamPaperService.class);
+    @Autowired
+    private PaperService paperService;
+    @Autowired
+    private PaperDetailService paperDetailService;
+
+    public void downloadPaper(List<Paper> oldPapers, String dirPath, String password) throws Exception {
+        if (oldPapers == null || oldPapers.size() == 0) {
+            throw new IllegalArgumentException("Paper list size is empty.");
+        }
+        log.info("exportPrintExamPaper start!");
+        //提取题库试卷的数据
+        List<PaperVo> papers = new ArrayList<>();
+        for (Paper oldPaper : oldPapers) {
+            List<PaperDetail> oldDetails = paperService.findPaperDetailsById(oldPaper.getId());
+            if (oldDetails == null || oldDetails.size() == 0) {
+                continue;
+            }
+            //封装试卷
+            PaperVo paper = new PaperVo();
+            paper.setId(oldPaper.getId());
+            paper.setName(oldPaper.getName());
+            paper.setCourseCode(oldPaper.getCourse().getCode());
+            paper.setCourseName(oldPaper.getCourse().getName());
+            paper.setTotalScore(oldPaper.getTotalScore());
+            paper.setDetailCount(oldPaper.getPaperDetailCount());
+            paper.setHasVideo(0);
+            List<PaperDetailVo> details = new ArrayList<>();
+            for (PaperDetail oldDetail : oldDetails) {
+                List<PaperDetailUnit> oldDetailUnits = paperDetailService.getUnitsByPaperDetailId(oldDetail.getId());
+                if (oldDetailUnits == null || oldDetailUnits.size() == 0) {
+                    continue;
+                }
+                //封装大题
+                PaperDetailVo detail = new PaperDetailVo();
+                detail.setNumber(oldDetail.getNumber());
+                detail.setName(oldDetail.getName());
+                detail.setTotalScore(oldDetail.getScore());
+                detail.setQuestionCount(oldDetail.getUnitCount());
+                List<QuestionVo> questions = new ArrayList<>();
+                for (int i = 0; i < oldDetailUnits.size(); i++) {
+                    PaperDetailUnit oldDetailUnit = oldDetailUnits.get(i);
+                    Question oldQuestion = oldDetailUnit.getQuestion();
+                    //封装试题
+                    QuestionVo question = new QuestionVo();
+                    question.setNumber(i + 1);
+                    question.setId(oldDetailUnit.getId());
+                    question.setScore(oldDetailUnit.getScore());
+                    question.setStructType(oldDetailUnit.getQuestionType().getId().intValue());
+                    question.setObjective(QuesStructType.isObjective(question.getStructType()));
+                    question.setBody(ConvertQuestion.parseBody(oldQuestion.getQuesBody()));
+                    question.setAnswer(ConvertQuestion.parseAnswer(oldQuestion.getQuesAnswer()));
+                    question.setOptions(ConvertQuestion.parseOption(oldQuestion));
+                    questions.add(question);
+
+                    //封装套题
+                    List<Question> oldSubQuestions = oldQuestion.getSubQuestions();
+                    if (oldSubQuestions == null || oldSubQuestions.size() == 0) {
+                        continue;
+                    }
+                    List<QuestionVo> subQuestions = new ArrayList<>();
+                    for (int j = 0; j < oldSubQuestions.size(); j++) {
+                        Question oldSubQuestion = oldSubQuestions.get(j);
+                        QuestionVo subQuestion = new QuestionVo();
+                        subQuestion.setNumber(j + 1);
+                        subQuestion.setId(oldSubQuestion.getId());
+                        subQuestion.setScore(oldSubQuestion.getScore());
+                        subQuestion.setStructType(oldSubQuestion.getQuestionType().getId().intValue());
+                        subQuestion.setObjective(QuesStructType.isObjective(subQuestion.getStructType()));
+                        subQuestion.setBody(ConvertQuestion.parseBody(oldSubQuestion.getQuesBody()));
+                        subQuestion.setAnswer(ConvertQuestion.parseAnswer(oldSubQuestion.getQuesAnswer()));
+                        subQuestion.setOptions(ConvertQuestion.parseOption(oldSubQuestion));
+                        subQuestions.add(subQuestion);
+                    }
+                    question.setSubQuestions(subQuestions);
+                }
+                detail.setQuestions(questions);
+                detail.setQuestionCount(questions.size());
+                details.add(detail);
+            }
+            paper.setDetails(details);
+            papers.add(paper);
+        }
+        this.convert(papers, dirPath, password);
+        log.info("exportPrintExamPaper end!");
+    }
+
+    /**
+     * 将题库试卷格式转换为分布式印刷的试卷格式
+     */
+    public void convert(List<PaperVo> papers, String dirPath, String password) throws Exception {
+        if (papers == null || papers.size() == 0) {
+            log.warn("No paper to convert.");
+            return;
+        }
+        //临时目录
+        dirPath = dirPath.replaceAll("\\\\", "/");
+        final String tempName = ExamFileType.PRINT_EXAM_PACKAGE.getName() + "_" + FileUtil.generateDateName();
+        final String tempDir = dirPath + "/" + tempName;
+        final String tempFilePath = dirPath + "/" + tempName + ".zip";
+        FileUtil.makeDirs(tempDir);
+
+        //汇总课程编码
+        Set<String> courseCodes = new HashSet<>();
+        for (PaperVo paper : papers) {
+            courseCodes.add(paper.getCourseCode());
+        }
+
+        //按"课程编码"封装试卷,数据文件转换保存到临时目录
+        this.parseCoursePapers(courseCodes, papers, tempDir, password);
+
+        //压缩转换后的数据包
+        File tempDirFile = new File(tempDir);
+        File tempFile = new File(tempFilePath);
+        FileUtil.doZip(tempDirFile, tempFile);
+        FileUtils.deleteQuietly(tempDirFile);
+    }
+
+    /**
+     * 按"课程编码"汇总试卷,数据文件转换保存到临时目录
+     */
+    private void parseCoursePapers(Set<String> courseCodes, List<PaperVo> papers, String tempDir, String password) {
+        //试卷和答案分开汇总到不同文件夹
+        final String paperDir = tempDir + "/paper";
+        final String answerDir = tempDir + "/answer";
+        String key = null;//加密密匙
+        if (StringUtils.isNotBlank(password)) {
+            //用密码生成密匙
+            key = Cryptogram.convertKey(password);
+        }
+        JsonMapper mapper = JsonMapper.nonNullMapper();
+        for (String courseCode : courseCodes) {
+            List<PaperDto> paperList = new ArrayList<>();
+            List<PaperAnswerDto> answerList = new ArrayList<>();
+            for (PaperVo paper : papers) {
+                if (!courseCode.equals(paper.getCourseCode())) {
+                    continue;
+                }
+                this.parsePaper(paper, paperList, answerList);
+            }
+            if (key != null) {
+                //加密试卷和答案
+                this.aesPaper(paperList, key);
+                this.aesAnswer(answerList, key);
+            }
+            List<PolicyDto> policyList = this.generatePolicy(paperList, courseCode);
+            FileUtil.saveAsFile(paperDir + "/" + courseCode + "/" + Constants.FILE_PAPER, mapper.toJson(paperList));
+            FileUtil.saveAsFile(paperDir + "/" + courseCode + "/" + Constants.FILE_POLICY, mapper.toJson(policyList));
+            FileUtil.saveAsFile(answerDir + "/" + courseCode + "/" + Constants.FILE_ANSWER, mapper.toJson(answerList));
+            //json = CommonUtils.replaceUnicodeStr(json);//todo
+        }
+        File paperZipFile = new File(tempDir + "/paper.zip");
+        File answerZipFile = new File(tempDir + "/answer.zip");
+        File paperDirFile = new File(paperDir);
+        File answerDirFile = new File(answerDir);
+        FileUtil.doZip(paperDirFile, paperZipFile);
+        FileUtil.doZip(answerDirFile, answerZipFile);
+        if (StringUtils.isNotBlank(password)) {
+            String sign = Cryptogram.md5Key(password);
+            FileUtil.appendHeader(paperZipFile, Constants.paperAesHeaders, sign);
+            FileUtil.appendHeader(answerZipFile, Constants.answerAesHeaders, sign);
+        } else {
+            FileUtil.appendHeader(paperZipFile, Constants.paperHeaders, null);
+            FileUtil.appendHeader(answerZipFile, Constants.answerHeaders, null);
+        }
+        paperZipFile.delete();
+        answerZipFile.delete();
+        //FileUtils.deleteQuietly(paperDirFile);
+        //FileUtils.deleteQuietly(answerDirFile);
+    }
+
+    /**
+     * 解析试卷
+     */
+    private void parsePaper(PaperVo paper, List<PaperDto> paperList, List<PaperAnswerDto> answerList) {
+        //试卷类型给默认值A-Z
+        String paperType = NumUtil.toEnNumber(paperList.size() + 1);
+        //封装试卷完整信息
+        PaperDto newPaper = new PaperDto(paper);
+        newPaper.setPaperType(paperType);
+        List<PaperDetailVo> details = paper.getDetails();
+        if (details == null || details.size() == 0) {
+            throw new IllegalArgumentException("试卷的大题不能为空!");
+        }
+        Double paperScore = 0d;//试卷总分
+        PaperAnswerDto newAnswer = new PaperAnswerDto(paper.getId());
+        List<PaperDetailDto> newDetails = new ArrayList<>();
+        for (PaperDetailVo detail : details) {
+            List<QuestionVo> questions = detail.getQuestions();
+            if (questions == null || questions.size() == 0) {
+                throw new IllegalArgumentException("试卷大题下的试题不能为空!");
+            }
+            Double detailScore = 0d;//大题总分
+            PaperDetailDto newDetail = new PaperDetailDto(detail);
+            for (QuestionVo question : questions) {
+                //封装试题
+                QuestionDto newQuestion = new QuestionDto(question);
+                //封装试题答案
+                SimpleQuestionDto simpleQuestion = new SimpleQuestionDto(question);
+                if (question.hasSubQuestion()) {
+                    Double questionScore = 0d;//套题总分
+                    for (QuestionVo subQuestion : question.getSubQuestions()) {
+                        //封装子试题
+                        QuestionDto newSubQuestion = new QuestionDto(subQuestion);
+                        newQuestion.addSubQuestion(newSubQuestion);
+                        //封装子试题答案
+                        SimpleQuestionDto subSimpleQuestion = new SimpleQuestionDto(subQuestion);
+                        subSimpleQuestion.setNumber(subQuestion.getNumber());
+                        simpleQuestion.addSubQuestion(subSimpleQuestion);
+                        questionScore += newSubQuestion.getScore();
+                    }
+                    newQuestion.setScore(questionScore);
+                }
+                detailScore += newQuestion.getScore();
+                newDetail.addQuestion(newQuestion);
+                newAnswer.addQuestion(simpleQuestion);
+            }
+            newDetail.setTotalScore(detailScore);
+            paperScore += detailScore;
+            newDetails.add(newDetail);
+        }
+        newPaper.setTotalScore(paperScore);
+        newPaper.setDetails(parseDetails(newDetails));
+        paperList.add(newPaper);
+        answerList.add(newAnswer);
+    }
+
+    /**
+     * 解析试卷试题
+     */
+    private List<PaperDetailDto> parseDetails(List<PaperDetailDto> details) {
+        //聚合同类题,并重新计算每道大题的总分以及题号顺序
+        List<PaperDetailDto> allDetails = new ArrayList<>();
+        PaperDetailDto singleDetail = new PaperDetailDto(QuesStructType.SINGLE_ANSWER_QUESTION.getName());
+        PaperDetailDto multipleDetail = new PaperDetailDto(QuesStructType.MULTIPLE_ANSWER_QUESTION.getName());
+        PaperDetailDto boolDetail = new PaperDetailDto(QuesStructType.BOOL_ANSWER_QUESTION.getName());
+        PaperDetailDto fillDetail = new PaperDetailDto(QuesStructType.FILL_BLANK_QUESTION.getName());
+        PaperDetailDto textDetail = new PaperDetailDto(QuesStructType.TEXT_ANSWER_QUESTION.getName());
+        PaperDetailDto nestedDetail = new PaperDetailDto(QuesStructType.NESTED_ANSWER_QUESTION.getName());
+        Integer singleNumber = 0, multipleNumber = 0, boolNumber = 0, fillNumber = 0, textNumber = 0, nestedNumber = 0;
+        Double singleScore = 0d, multipleScore = 0d, boolScore = 0d, fillScore = 0d, textScore = 0d, nestedScore = 0d;
+        for (PaperDetailDto detail : details) {
+            for (QuestionDto question : detail.getQuestions()) {
+                if (QuesStructType.SINGLE_ANSWER_QUESTION.getId() == question.getStructType()) {
+                    question.setNumber(++singleNumber);
+                    singleScore += question.getScore();
+                    singleDetail.setTotalScore(singleScore);
+                    singleDetail.addQuestion(question);
+                } else if (QuesStructType.MULTIPLE_ANSWER_QUESTION.getId() == question.getStructType()) {
+                    question.setNumber(++multipleNumber);
+                    multipleScore += question.getScore();
+                    multipleDetail.setTotalScore(multipleScore);
+                    multipleDetail.addQuestion(question);
+                } else if (QuesStructType.BOOL_ANSWER_QUESTION.getId() == question.getStructType()) {
+                    question.setNumber(++boolNumber);
+                    boolScore += question.getScore();
+                    boolDetail.setTotalScore(boolScore);
+                    boolDetail.addQuestion(question);
+                } else if (QuesStructType.FILL_BLANK_QUESTION.getId() == question.getStructType()) {
+                    question.setNumber(++fillNumber);
+                    fillScore += question.getScore();
+                    fillDetail.setTotalScore(fillScore);
+                    fillDetail.addQuestion(question);
+                } else if (QuesStructType.TEXT_ANSWER_QUESTION.getId() == question.getStructType()) {
+                    question.setNumber(++textNumber);
+                    textScore += question.getScore();
+                    textDetail.setTotalScore(textScore);
+                    textDetail.addQuestion(question);
+                } else if (QuesStructType.NESTED_ANSWER_QUESTION.getId() == question.getStructType()) {
+                    question.setNumber(++nestedNumber);
+                    nestedScore += question.getScore();
+                    nestedDetail.setTotalScore(nestedScore);
+                    nestedDetail.addQuestion(question);
+                }
+            }
+        }
+        int number = 0;
+        if (singleDetail.getQuestions().size() > 0) {
+            singleDetail.setNumber(++number);
+            allDetails.add(singleDetail);
+        }
+        if (multipleDetail.getQuestions().size() > 0) {
+            multipleDetail.setNumber(++number);
+            allDetails.add(multipleDetail);
+        }
+        if (boolDetail.getQuestions().size() > 0) {
+            boolDetail.setNumber(++number);
+            allDetails.add(boolDetail);
+        }
+        if (fillDetail.getQuestions().size() > 0) {
+            fillDetail.setNumber(++number);
+            allDetails.add(fillDetail);
+        }
+        if (textDetail.getQuestions().size() > 0) {
+            textDetail.setNumber(++number);
+            allDetails.add(textDetail);
+        }
+        if (nestedDetail.getQuestions().size() > 0) {
+            nestedDetail.setNumber(++number);
+            allDetails.add(nestedDetail);
+        }
+        return allDetails;
+    }
+
+    /**
+     * 生成调卷规则
+     */
+    private List<PolicyDto> generatePolicy(List<PaperDto> papers, String courseCode) {
+        List<PolicyDto> policyList = new ArrayList<>();
+        Map<String, List<String>> maps = new HashMap<>();
+        for (PaperDto paper : papers) {
+            //按试卷类型封装试卷ID
+            List<String> ids = maps.get(paper.getPaperType());
+            if (ids == null) {
+                ids = new ArrayList<>();
+            }
+            ids.add(paper.getId());
+            maps.put(paper.getPaperType(), ids);
+        }
+        //生成默认调卷规则
+        for (Map.Entry<String, List<String>> entry : maps.entrySet()) {
+            PolicyDto policy = new PolicyDto();
+            policy.setType(PolicyType.Random.getId());
+            policy.setObjectiveShuffle(false);
+            policy.setOptionShuffle(false);
+            policy.setCourseCode(courseCode);
+            policy.setPaperType(entry.getKey());
+            List<String> ids = entry.getValue();
+            if (ids.size() == 0) {
+                continue;
+            }
+            //计算每份试卷的随机抽取权重
+            double weight = 1d / ids.size();
+            for (String id : ids) {
+                policy.addWeight(new PolicyWeightDto(id, weight));
+            }
+            policyList.add(policy);
+        }
+        return policyList;
+    }
+
+    /**
+     * 加密试卷
+     */
+    private void aesPaper(List<PaperDto> papers, String key) {
+        log.info("aesPaper..." + key);
+        for (PaperDto paper : papers) {
+            List<PaperDetailDto> details = paper.getDetails();
+            for (PaperDetailDto detail : details) {
+                List<QuestionDto> questions = detail.getQuestions();
+                for (QuestionDto question : questions) {
+                    List<QuestionOptionDto> options = question.getOptions();
+                    if (options != null) {
+                        for (QuestionOptionDto option : options) {
+                            String newBody = Cryptogram.aesEncrypt(option.getBody(), key);//加密选项内容
+                            option.setBody(newBody);
+                        }
+                    }
+                    List<QuestionDto> subQuestions = question.getSubQuestions();
+                    if (subQuestions != null) {
+                        for (QuestionDto subQuestion : subQuestions) {
+                            List<QuestionOptionDto> subOptions = subQuestion.getOptions();
+                            if (subOptions != null) {
+                                for (QuestionOptionDto option : subOptions) {
+                                    String newBody = Cryptogram.aesEncrypt(option.getBody(), key);//加密(子题)选项内容
+                                    option.setBody(newBody);
+                                }
+                            }
+                            String newBody = Cryptogram.aesEncrypt(subQuestion.getBody(), key);//加密(子题)题干内容
+                            subQuestion.setBody(newBody);
+                        }
+                    }
+                    String newBody = Cryptogram.aesEncrypt(question.getBody(), key);//加密题干内容
+                    question.setBody(newBody);
+                }
+            }
+        }
+    }
+
+    /**
+     * 加密试卷答案
+     */
+    private void aesAnswer(List<PaperAnswerDto> papers, String key) {
+        log.info("aesAnswer..." + key);
+        for (PaperAnswerDto paper : papers) {
+            List<SimpleQuestionDto> questions = paper.getQuestions();
+            for (SimpleQuestionDto question : questions) {
+                List<SimpleQuestionDto> subQuestions = question.getSubQuestions();
+                if (subQuestions != null) {
+                    for (SimpleQuestionDto subQuestion : subQuestions) {
+                        String newAnswer = Cryptogram.aesEncrypt(subQuestion.getAnswer(), key);//加密答案内容
+                        subQuestion.setAnswer(newAnswer);
+                    }
+                }
+                String newAnswer = Cryptogram.aesEncrypt(question.getAnswer(), key);//加密答案内容
+                question.setAnswer(newAnswer);
+            }
+        }
+    }
+
+    /**
+     * 解压并提取JSON文件
+     */
+    private List<File> parseDataFiles(final String dirPath, File zipFile) throws Exception {
+        List<File> dataFileList = new ArrayList<>();
+        //解压当前文件
+        List<File> fileList = FileUtil.unZip(new File(dirPath), zipFile);
+        if (fileList == null || fileList.size() == 0) {
+            return dataFileList;
+        }
+        //解压当前文件内的其它ZIP文件,并提取JSON文件
+        for (File curFile : fileList) {
+            if (curFile.getName().toLowerCase().endsWith(Constants.ZIP)) {
+                final String curDir = FileUtil.getFilePathName(curFile.getAbsolutePath());
+                List<File> files = FileUtil.unZip(new File(curDir), curFile);
+                if (files == null || files.size() == 0) {
+                    continue;
+                }
+                for (File file : files) {
+                    if (file.getName().toLowerCase().endsWith(Constants.JSON)) {
+                        dataFileList.add(file);
+                    }
+                }
+            } else if (curFile.getName().toLowerCase().endsWith(Constants.JSON)) {
+                dataFileList.add(curFile);
+            }
+        }
+        return dataFileList;
+    }
+
+}

+ 636 - 649
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/ExportPaperServiceImpl.java

@@ -1,29 +1,29 @@
 package cn.com.qmth.examcloud.core.questions.service.impl;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.servlet.http.HttpServletResponse;
-
+import cn.com.qmth.examcloud.common.dto.question.enums.QuesStructType;
+import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
+import cn.com.qmth.examcloud.core.questions.base.FileDisposeUtil;
+import cn.com.qmth.examcloud.core.questions.base.SpringContextUtils;
+import cn.com.qmth.examcloud.core.questions.base.enums.ExamFileType;
+import cn.com.qmth.examcloud.core.questions.base.word.DocxProcessUtil;
+import cn.com.qmth.examcloud.core.questions.dao.CoursePropertyRepo;
+import cn.com.qmth.examcloud.core.questions.dao.PaperRepo;
+import cn.com.qmth.examcloud.core.questions.dao.QuestionAudioRepo;
+import cn.com.qmth.examcloud.core.questions.dao.entity.*;
+import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.*;
+import cn.com.qmth.examcloud.core.questions.service.ExportPaperService;
+import cn.com.qmth.examcloud.core.questions.service.PaperDetailService;
+import cn.com.qmth.examcloud.core.questions.service.PaperService;
+import cn.com.qmth.examcloud.core.questions.service.PropertyService;
+import cn.com.qmth.examcloud.core.questions.service.bean.dto.QuestionDistributeDto;
+import cn.com.qmth.examcloud.core.questions.service.converter.PrintExamPaperService;
+import cn.com.qmth.examcloud.core.questions.service.export.ExportPaperAbstractService;
+import com.google.common.collect.Lists;
+import com.google.gson.Gson;
 import main.java.com.UpYun;
-
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
@@ -37,675 +37,662 @@ import org.springframework.data.mongodb.core.query.Criteria;
 import org.springframework.data.mongodb.core.query.Query;
 import org.springframework.stereotype.Service;
 
-import cn.com.qmth.examcloud.common.dto.question.enums.QuesStructType;
-
-import com.google.gson.Gson;
-import cn.com.qmth.examcloud.core.questions.dao.PaperRepo;
-import cn.com.qmth.examcloud.core.questions.service.bean.dto.QuestionDistributeDto;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Paper;
-import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetail;
-import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetailUnit;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.Block;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestOption;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestPaper;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestPaperDetail;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.ComputerTestQuestion;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.Section;
-import cn.com.qmth.examcloud.core.questions.dao.entity.computerTestModel.Sections;
-import cn.com.qmth.examcloud.core.questions.service.ExportPaperService;
-import cn.com.qmth.examcloud.core.questions.service.PaperDetailService;
-import cn.com.qmth.examcloud.core.questions.service.PaperService;
-import cn.com.qmth.examcloud.core.questions.service.export.ExportPaperAbstractService;
-import cn.com.qmth.examcloud.core.questions.dao.CoursePropertyRepo;
-import cn.com.qmth.examcloud.core.questions.dao.QuestionAudioRepo;
-import cn.com.qmth.examcloud.core.questions.dao.entity.CourseProperty;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Property;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuestionAudio;
-import cn.com.qmth.examcloud.core.questions.service.PropertyService;
-import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
-import cn.com.qmth.examcloud.core.questions.base.FileDisposeUtil;
-import cn.com.qmth.examcloud.core.questions.base.SpringContextUtils;
-import cn.com.qmth.examcloud.core.questions.base.word.DocxProcessUtil;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 
 @Service("exportPaperService")
-public class ExportPaperServiceImpl implements ExportPaperService{
-	
-	public static final String TEMP_FILE_EXP = "docxExport/";
-	
-	public static final String TEMP_FILE_NAME = "_考试说明.docx";
-	
-	@Autowired
-	private PaperRepo paperRepo;
-	
-	@Autowired
-	private PaperService paperService;
-	
-	@Autowired
-	private PaperDetailService paperDetailService;
-	
-	@Autowired
+public class ExportPaperServiceImpl implements ExportPaperService {
+
+    public static final String TEMP_FILE_EXP = "docxExport/";
+
+    public static final String TEMP_FILE_NAME = "_考试说明.docx";
+
+    @Autowired
+    private PaperRepo paperRepo;
+
+    @Autowired
+    private PaperService paperService;
+
+    @Autowired
+    private PaperDetailService paperDetailService;
+
+    @Autowired
     private MongoTemplate mongoTemplate;
-	
-	@Autowired
-	private CoursePropertyRepo coursePropertyRepo;
-	
-	@Autowired
-	private PropertyService propertyService;
-	
-	@Autowired
-	private QuestionAudioRepo questionAudioRepo;
-	
-	@Value("${upyun.bucketName}")
-	protected String bucketName;
-	
-	@Value("${upyun.userName}")
-	protected String userName;
-	
-	@Value("${upyun.password}")
-	protected String password;
-
-	@Override
-	public void exportPaperFile(String paperId,String serviceName,String exportContentList,HttpServletResponse response,String loginName, String examType) throws Exception {
-		ExportPaperAbstractService exportPaperAbstractService = (ExportPaperAbstractService) SpringContextUtils.getBeanById("tjdxExportPaperService");
-		//根据试卷id查询试卷 
-		Paper paper = paperRepo.findOne(paperId);
-		List<Paper> papers = new ArrayList<Paper>();
-		papers.add(paper);
-		String zipFileName = loginName + System.currentTimeMillis() + "";
-		File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
-		if(!directory.exists()){
-			directory.mkdirs();
-		}
-		if(exportContentList.indexOf("COMPUTERTEST_PACKAGE")>-1){
-			downJson(paper,zipFileName);
-		}
-		if(exportContentList.indexOf("PAPER")>-1){
-			exportPaperAbstractService.downloadPaper(paperId,zipFileName,examType);
-		}
-		if(exportContentList.indexOf("ANSWER")>-1){
-			exportPaperAbstractService.downloadPaperAnswer(paperId,zipFileName);
-		}
-		//下载考试说明	2018-2-27	weiwehai
+
+    @Autowired
+    private CoursePropertyRepo coursePropertyRepo;
+
+    @Autowired
+    private PropertyService propertyService;
+
+    @Autowired
+    private QuestionAudioRepo questionAudioRepo;
+
+    @Autowired
+    private PrintExamPaperService printExamPaperService;
+
+    @Value("${upyun.bucketName}")
+    protected String bucketName;
+
+    @Value("${upyun.userName}")
+    protected String userName;
+
+    @Value("${upyun.password}")
+    protected String password;
+
+    @Override
+    public void exportPaperFile(String paperId, String serviceName, String exportContentList, HttpServletResponse response, String loginName, String examType, String psw) throws Exception {
+        ExportPaperAbstractService exportPaperAbstractService = (ExportPaperAbstractService) SpringContextUtils.getBeanById("tjdxExportPaperService");
+        //根据试卷id查询试卷
+        Paper paper = paperRepo.findOne(paperId);
+
+        String zipFileName = loginName + System.currentTimeMillis() + "";
+        File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
+        if (!directory.exists()) {
+            directory.mkdirs();
+        }
+
+        if (exportContentList.indexOf(ExamFileType.PRINT_EXAM_PACKAGE.name()) > -1) {
+            printExamPaperService.downloadPaper(Lists.newArrayList(paper), directory.getAbsolutePath(), psw);
+        }
+
+        if (exportContentList.indexOf(ExamFileType.COMPUTERTEST_PACKAGE.name()) > -1) {
+            downJson(paper, zipFileName);
+        }
+
+        if (exportContentList.indexOf(ExamFileType.PAPER.name()) > -1) {
+            exportPaperAbstractService.downloadPaper(paperId, zipFileName, examType);
+        }
+
+        if (exportContentList.indexOf(ExamFileType.ANSWER.name()) > -1) {
+            exportPaperAbstractService.downloadPaperAnswer(paperId, zipFileName);
+        }
+
+        //下载考试说明	2018-2-27	weiwehai
 		/*if(examType.equals("offLine") && StringUtils.isNotBlank(paper.getExamRemark())){
 			downExamRemark(paper,zipFileName);
 		}*/
-		FileDisposeUtil.fileToZip(TEMP_FILE_EXP+File.separator+zipFileName,TEMP_FILE_EXP,zipFileName);
-		FileDisposeUtil.downloadFile(paper.getName()+"_"+paper.getCourse().getCode()+".zip", TEMP_FILE_EXP+File.separator+zipFileName+".zip",response);
-		deteleFolder(TEMP_FILE_EXP,zipFileName);
-	}
-	
-	/**
-	 * 下载考试说明
-	 * @param examRemark
-	 * @param zipFileName
-	 * @throws Exception 
-	 */
-	private void downExamRemark(Paper paper,String zipFileName) throws Exception {
-		//1.考试说明html转成word
-		String title = "<p style=\"text-align:center\"><span style=\"font-size:26px\"><span style=\"font-family:宋体\">考&nbsp;试&nbsp;说&nbsp;明</span></span></p>";
-		WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
-		DocxProcessUtil.html2Docx(wordMLPackage, CommonUtils.formatHtml(title+paper.getExamRemark()));
-		//2.导出考试说明word	
-		File file = new File(TEMP_FILE_EXP+File.separator+zipFileName+File.separator+paper.getCourse().getCode()+TEMP_FILE_NAME);
-		Docx4J.save(wordMLPackage, file);
-	}
-
-	private void deteleFolder(String sourceFilePath,String zipFileName) {
-		File ComputerTestPaperfoler = new File(sourceFilePath + File.separator + "json");
-		if(ComputerTestPaperfoler.exists()){
-			FileUtils.deleteQuietly(ComputerTestPaperfoler);
-		}
-		File zipFolder = new File(sourceFilePath + File.separator + zipFileName);
-		if(zipFolder.exists()){
-			FileUtils.deleteQuietly(zipFolder);
-		}
-		File zipFile = new File(sourceFilePath + File.separator + zipFileName + ".zip");
-		if(zipFile.exists()){
-			FileUtils.deleteQuietly(zipFile);
-		}
-	}
-
-	private void downJson(Paper paper,String zipFileName) {
-		ComputerTestPaper computerTestPaper = buildComputerTestPapers(paper);
-		String jsonDirectory = TEMP_FILE_EXP + File.separator + "json";
-		//新建文件夹
-		File dirFile = new File(jsonDirectory);
-		if(!dirFile.exists()){
-			dirFile.mkdirs();
-		}
-		makeComputerTestPaperToJsonFile(paper.getCourse().getCode(),computerTestPaper,jsonDirectory);
-		downloadAudio(computerTestPaper,jsonDirectory);
-		//将文件夹打包成zip压缩包放在docxExport下
-		FileDisposeUtil.fileToZip(jsonDirectory,TEMP_FILE_EXP+File.separator+zipFileName,paper.getCourse().getCode()+"_"+paper.getName());
-	}
-	
-	 private void downloadAudio(ComputerTestPaper computerTestPaper,String jsonDirectory) {
-		//取到所有大题
-		List<ComputerTestPaperDetail> details = computerTestPaper.getDetails();
-		if(details != null && details.size()>0){
-			for(ComputerTestPaperDetail detail:details){
-				//取到所有小题集合
-				List<ComputerTestQuestion> questions = detail.getQuestions();
-				if(questions != null && questions.size()>0){
-					for(ComputerTestQuestion question:questions){
-						int bodyNum = 1;
-						//取到题干
-						Sections body = question.getBody();
-						List<Section> sections = body.getSections();
-						for(Section section:sections){
-							List<Block> blocks = section.getBlocks();
-							if(blocks != null && blocks.size()>0){
-								for(Block block:blocks){
-									if(block.getType().equals("audio")){
-										String id = block.getValue();
-										QuestionAudio questionAudio = questionAudioRepo.findOne(id);
-										String audioFileName = computerTestPaper.getCourseCode() + "_" +
-															 	computerTestPaper.getName() + "_" +"_试卷_"+
-															 	detail.getNumber()+"_"+question.getNumber()+
-															 	"_1_"+bodyNum+"."+ questionAudio.getFileSuffixes();
-										UpYun upyun = new UpYun(bucketName,userName,password);
-										File file = new File(jsonDirectory+File.separator+audioFileName);
-										upyun.readFile(questionAudio.getFileUrl(), file);
-										bodyNum++;
-									}
-								}
-							}
-						}
-						//取到选项
-						List<ComputerTestOption> options = question.getOptions();
-						if(options != null && options.size()>0){
-							for(ComputerTestOption computerTestOption:options){
-								int optionNum = 1;
-								//获取选项主体
-								Sections optionBody = computerTestOption.getBody();
-								List<Section> optionSections = optionBody.getSections();
-								if(optionSections != null && optionSections.size()>0){
-									for(Section optionSection:optionSections){
-										List<Block> blocks = optionSection.getBlocks();
-										if(blocks != null && blocks.size()>0){
-											for(Block block:blocks){
-												if(block.getType().equals("audio")){
-													String id = block.getValue();
-													QuestionAudio questionAudio = questionAudioRepo.findOne(id);
-													String audioFileName = computerTestPaper.getCourseCode() + "_" +
-																		 	computerTestPaper.getName() + "_" +"_试卷_"+
-																		 	detail.getNumber()+"_"+question.getNumber()+
-																		 	"_2_"+computerTestOption.getNumber()+"_"+optionNum +"."+ questionAudio.getFileSuffixes();
-													UpYun upyun = new UpYun(bucketName,userName,password);
-													File file = new File(jsonDirectory+File.separator+audioFileName);
-													upyun.readFile(questionAudio.getFileUrl(), file);
-													optionNum++;
-												}
-											}
-										}
-									}
-								}
-							}
-						}
-					}
-				}
-			}
-		}
-	}
-
-	/**
+        FileDisposeUtil.fileToZip(TEMP_FILE_EXP + File.separator + zipFileName, TEMP_FILE_EXP, zipFileName);
+        FileDisposeUtil.downloadFile(paper.getName() + "_" + paper.getCourse().getCode() + ".zip", TEMP_FILE_EXP + File.separator + zipFileName + ".zip", response);
+        deteleFolder(TEMP_FILE_EXP, zipFileName);
+    }
+
+    /**
+     * 下载考试说明
+     *
+     * @param zipFileName
+     * @throws Exception
+     */
+    private void downExamRemark(Paper paper, String zipFileName) throws Exception {
+        //1.考试说明html转成word
+        String title = "<p style=\"text-align:center\"><span style=\"font-size:26px\"><span style=\"font-family:宋体\">考&nbsp;试&nbsp;说&nbsp;明</span></span></p>";
+        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
+        DocxProcessUtil.html2Docx(wordMLPackage, CommonUtils.formatHtml(title + paper.getExamRemark()));
+        //2.导出考试说明word
+        File file = new File(TEMP_FILE_EXP + File.separator + zipFileName + File.separator + paper.getCourse().getCode() + TEMP_FILE_NAME);
+        Docx4J.save(wordMLPackage, file);
+    }
+
+    private void deteleFolder(String sourceFilePath, String zipFileName) {
+        File ComputerTestPaperfoler = new File(sourceFilePath + File.separator + "json");
+        if (ComputerTestPaperfoler.exists()) {
+            FileUtils.deleteQuietly(ComputerTestPaperfoler);
+        }
+        File zipFolder = new File(sourceFilePath + File.separator + zipFileName);
+        if (zipFolder.exists()) {
+            FileUtils.deleteQuietly(zipFolder);
+        }
+        File zipFile = new File(sourceFilePath + File.separator + zipFileName + ".zip");
+        if (zipFile.exists()) {
+            FileUtils.deleteQuietly(zipFile);
+        }
+    }
+
+    private void downJson(Paper paper, String zipFileName) {
+        ComputerTestPaper computerTestPaper = buildComputerTestPapers(paper);
+        String jsonDirectory = TEMP_FILE_EXP + File.separator + "json";
+        //新建文件夹
+        File dirFile = new File(jsonDirectory);
+        if (!dirFile.exists()) {
+            dirFile.mkdirs();
+        }
+        makeComputerTestPaperToJsonFile(paper.getCourse().getCode(), computerTestPaper, jsonDirectory);
+        downloadAudio(computerTestPaper, jsonDirectory);
+        //将文件夹打包成zip压缩包放在docxExport下
+        FileDisposeUtil.fileToZip(jsonDirectory, TEMP_FILE_EXP + File.separator + zipFileName, paper.getCourse().getCode() + "_" + paper.getName());
+    }
+
+    private void downloadAudio(ComputerTestPaper computerTestPaper, String jsonDirectory) {
+        //取到所有大题
+        List<ComputerTestPaperDetail> details = computerTestPaper.getDetails();
+        if (details != null && details.size() > 0) {
+            for (ComputerTestPaperDetail detail : details) {
+                //取到所有小题集合
+                List<ComputerTestQuestion> questions = detail.getQuestions();
+                if (questions != null && questions.size() > 0) {
+                    for (ComputerTestQuestion question : questions) {
+                        int bodyNum = 1;
+                        //取到题干
+                        Sections body = question.getBody();
+                        List<Section> sections = body.getSections();
+                        for (Section section : sections) {
+                            List<Block> blocks = section.getBlocks();
+                            if (blocks != null && blocks.size() > 0) {
+                                for (Block block : blocks) {
+                                    if (block.getType().equals("audio")) {
+                                        String id = block.getValue();
+                                        QuestionAudio questionAudio = questionAudioRepo.findOne(id);
+                                        String audioFileName = computerTestPaper.getCourseCode() + "_" +
+                                                computerTestPaper.getName() + "_" + "_试卷_" +
+                                                detail.getNumber() + "_" + question.getNumber() +
+                                                "_1_" + bodyNum + "." + questionAudio.getFileSuffixes();
+                                        UpYun upyun = new UpYun(bucketName, userName, password);
+                                        File file = new File(jsonDirectory + File.separator + audioFileName);
+                                        upyun.readFile(questionAudio.getFileUrl(), file);
+                                        bodyNum++;
+                                    }
+                                }
+                            }
+                        }
+                        //取到选项
+                        List<ComputerTestOption> options = question.getOptions();
+                        if (options != null && options.size() > 0) {
+                            for (ComputerTestOption computerTestOption : options) {
+                                int optionNum = 1;
+                                //获取选项主体
+                                Sections optionBody = computerTestOption.getBody();
+                                List<Section> optionSections = optionBody.getSections();
+                                if (optionSections != null && optionSections.size() > 0) {
+                                    for (Section optionSection : optionSections) {
+                                        List<Block> blocks = optionSection.getBlocks();
+                                        if (blocks != null && blocks.size() > 0) {
+                                            for (Block block : blocks) {
+                                                if (block.getType().equals("audio")) {
+                                                    String id = block.getValue();
+                                                    QuestionAudio questionAudio = questionAudioRepo.findOne(id);
+                                                    String audioFileName = computerTestPaper.getCourseCode() + "_" +
+                                                            computerTestPaper.getName() + "_" + "_试卷_" +
+                                                            detail.getNumber() + "_" + question.getNumber() +
+                                                            "_2_" + computerTestOption.getNumber() + "_" + optionNum + "." + questionAudio.getFileSuffixes();
+                                                    UpYun upyun = new UpYun(bucketName, userName, password);
+                                                    File file = new File(jsonDirectory + File.separator + audioFileName);
+                                                    upyun.readFile(questionAudio.getFileUrl(), file);
+                                                    optionNum++;
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * 构建机考数据包实体类
-     * @param extractConfig
+     *
      * @return
      */
-    private ComputerTestPaper buildComputerTestPapers(Paper paper){
-    		//得到所有旧对象的大题对象
-    		List<PaperDetail> paperDetails = paperService.findPaperDetailsById(paper.getId());
-    		//通过 paper 对象 ,生成新的  ComputerTestPaper 对象
-    		ComputerTestPaper computerTestPaper = new ComputerTestPaper(paper,"");
-    		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(getBodyOrAnswer(paperDetailUnit.getQuestion().getQuesBody()));
-    				//得到小题所有选项
-    				computerTestQuestion.setOptions(getOption(paperDetailUnit.getQuestion()));
-    				//得到小题的答案
-    				computerTestQuestion.setAnswer(getBodyOrAnswer(paperDetailUnit.getQuestion().getQuesAnswer()));
-    				//查询小题中的 套题
-    				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(getBodyOrAnswer(subQuestion.getQuesBody()));
-        					subcomputerTestQuestion.setOptions(getOption(subQuestion));
-        					subcomputerTestQuestion.setAnswer(getBodyOrAnswer(subQuestion.getQuesAnswer()));
-        					subQuestions.add(subcomputerTestQuestion);
-    					}
-        				computerTestQuestion.setSubQuestions(subQuestions);
-    				}
-    				questions.add(computerTestQuestion);
-    			}
-    			computerTestPaperDetail.setQuestions(questions);
-    			//paperDetail中的题数(unitCount)可能不准确,这里以questions的实际size为准
-    			computerTestPaperDetail.setQuestionCount(questions.size());
-    			details.add(computerTestPaperDetail);
-    		}
-    		computerTestPaper.setDetails(details);
-    	return computerTestPaper;
+    public ComputerTestPaper buildComputerTestPapers(Paper paper) {
+        //得到所有旧对象的大题对象
+        List<PaperDetail> paperDetails = paperService.findPaperDetailsById(paper.getId());
+        //通过 paper 对象 ,生成新的  ComputerTestPaper 对象
+        ComputerTestPaper computerTestPaper = new ComputerTestPaper(paper, "");
+        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(getBodyOrAnswer(paperDetailUnit.getQuestion().getQuesBody()));
+                //得到小题所有选项
+                computerTestQuestion.setOptions(getOption(paperDetailUnit.getQuestion()));
+                //得到小题的答案
+                computerTestQuestion.setAnswer(getBodyOrAnswer(paperDetailUnit.getQuestion().getQuesAnswer()));
+                //查询小题中的 套题
+                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(getBodyOrAnswer(subQuestion.getQuesBody()));
+                        subcomputerTestQuestion.setOptions(getOption(subQuestion));
+                        subcomputerTestQuestion.setAnswer(getBodyOrAnswer(subQuestion.getQuesAnswer()));
+                        subQuestions.add(subcomputerTestQuestion);
+                    }
+                    computerTestQuestion.setSubQuestions(subQuestions);
+                }
+                questions.add(computerTestQuestion);
+            }
+            computerTestPaperDetail.setQuestions(questions);
+            //paperDetail中的题数(unitCount)可能不准确,这里以questions的实际size为准
+            computerTestPaperDetail.setQuestionCount(questions.size());
+            details.add(computerTestPaperDetail);
+        }
+        computerTestPaper.setDetails(details);
+        return computerTestPaper;
     }
-    
-    private Sections getBodyOrAnswer(String str){
-    	Sections body = new Sections();
-		List<Section> sections = new ArrayList<Section>();
-		//得到小题题干或者答案行数
-		if(StringUtils.isBlank(str)){
-			return body;
-		}
-		String[] questionRowStrings = str.split("</p>");
-		for(int i = 0;i<questionRowStrings.length;i++){
-			if(disposeQuestionBodyOrOption(questionRowStrings[i]) != null && disposeQuestionBodyOrOption(questionRowStrings[i]).size()>0){
-				Section section = new Section();
-				//将小题题干拆分为Block集合
-				section.setBlocks(disposeQuestionBodyOrOption(questionRowStrings[i]));
-				sections.add(section);
-			}
-		}
-		body.setSections(sections);
-		return body;
+
+    private Sections getBodyOrAnswer(String str) {
+        Sections body = new Sections();
+        List<Section> sections = new ArrayList<Section>();
+        //得到小题题干或者答案行数
+        if (StringUtils.isBlank(str)) {
+            return body;
+        }
+        String[] questionRowStrings = str.split("</p>");
+        for (int i = 0; i < questionRowStrings.length; i++) {
+            List<Block> blocks = disposeQuestionBodyOrOption(questionRowStrings[i]);
+            if (blocks != null && blocks.size() > 0) {
+                Section section = new Section();
+                //将小题题干拆分为Block集合
+                section.setBlocks(blocks);
+                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++){
-					if(disposeQuestionBodyOrOption(optionStrings[i]) != null && disposeQuestionBodyOrOption(optionStrings[i]).size()>0){
-						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<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++) {
+                    List<Block> blocks = disposeQuestionBodyOrOption(optionStrings[i]);
+                    if (blocks != null && blocks.size() > 0) {
+                        Section section = new Section();
+                        section.setBlocks(blocks);
+                        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.setPlayTime(1);
-				block.setType("audio");
-				block.setValue(CommonUtils.getAttrValue(questionRowStrings[i],"id"));
-				blocks.add(block);
-			}else{
-				block.setType("text");
-				questionRowStrings[i] = questionRowStrings[i].replace("&nbsp;","");//消除空格
-				questionRowStrings[i] = questionRowStrings[i].replace("&quot;","\"");//将&quot;转换成\"
-				questionRowStrings[i] = questionRowStrings[i].replace("&lt;","<");//将&lt;转换成<
-				questionRowStrings[i] = questionRowStrings[i].replace("&gt;",">");//将&gt;转换成>
-				questionRowStrings[i] = questionRowStrings[i].replace("&amp;","&");//将&amp;转换成&
-				if(StringUtils.isNotBlank(questionRowStrings[i])){
-					block.setValue(questionRowStrings[i]);
-					blocks.add(block);
-				}
-			}
-    	}
-		return blocks;
-	}
-    
+        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();
+            String rowStr = questionRowStrings[i];
+            //判断是否有图片
+            if (rowStr.startsWith("img")) {
+                rowStr = "<" + rowStr + ">";
+                Map<String, Object> param = new HashMap<String, Object>();
+                //需要继续做截取,取到Parma
+                block.setType("image");
+                //获取图片的路径
+                List<String> strSrcList = getImg(rowStr, "src");
+                if (strSrcList.size() > 0) {
+                    String strSrc = strSrcList.get(0).replaceAll("src=\"", "").replaceAll("\"", "");
+                    block.setValue(strSrc);
+                }
+                //获取图片的高度
+                List<String> strHeightList = getImg(rowStr, "height");
+                if (strHeightList.size() > 0) {
+                    String strHeight = strHeightList.get(0).replaceAll("height=\"", "").replaceAll("\"", "");
+                    param.put("height", strHeight);
+                }
+                //获取图片的宽度
+                List<String> strWidthList = getImg(rowStr, "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 (rowStr.startsWith("a")
+                    && rowStr.contains("id")
+                    && rowStr.contains("name")) {    //处理音频
+                rowStr = "<" + rowStr + ">";
+                block.setPlayTime(1);
+                block.setType("audio");
+                block.setValue(CommonUtils.getAttrValue(rowStr, "id"));
+                blocks.add(block);
+            } else {
+                block.setType("text");
+                rowStr = rowStr.replace("&nbsp;", "");//消除空格
+                rowStr = rowStr.replace("&quot;", "\"");//将&quot;转换成\"
+                rowStr = rowStr.replace("&lt;", "<");//将&lt;转换成<
+                rowStr = rowStr.replace("&gt;", ">");//将&gt;转换成>
+                rowStr = rowStr.replace("&amp;", "&");//将&amp;转换成&
+                if (StringUtils.isNotBlank(rowStr)) {
+                    block.setValue(rowStr);
+                    blocks.add(block);
+                }
+            }
+        }
+        return blocks;
+    }
+
     /**
      * 获取图片里面的路径,长度,宽度
+     *
      * @param s
      * @param str
      * @return
      */
-    private List<String> getImg(String s,String str)
-    {
+    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())
-        {
+        while (ma.find()) {
             list.add(ma.group());
         }
         return list;
     }
-    
+
     /**
      * 将computerTestPaper对象生成JSON文件存放在jsonDirectoryPath中
-     * @param extractConfig
+     *
      * @param computerTestPaper
      * @param jsonDirectoryPath
      */
-    private void makeComputerTestPaperToJsonFile(String courseCode,ComputerTestPaper computerTestPaper,String jsonDirectoryPath){
-		//创建新的JSON文件
-		File file = new File(jsonDirectoryPath + File.separator+courseCode+".json");
-		//将对象转成 json对象
-		Gson gson = new Gson();
-		String strJSON = gson.toJson(computerTestPaper);
-		
-		strJSON = CommonUtils.replaceUnicodeStr(strJSON);
-		//生成文件流写入JSON文件
-		FileOutputStream outputStream = null;
-		try {
-			outputStream = new FileOutputStream(file);
-			byte b[] = strJSON.getBytes();
-			outputStream.write(b);
-			outputStream.flush();
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
-		} finally{
-			IOUtils.closeQuietly(outputStream);
-		}
+    private void makeComputerTestPaperToJsonFile(String courseCode, ComputerTestPaper computerTestPaper, String jsonDirectoryPath) {
+        //创建新的JSON文件
+        File file = new File(jsonDirectoryPath + File.separator + courseCode + ".json");
+        //将对象转成 json对象
+        Gson gson = new Gson();
+        String strJSON = gson.toJson(computerTestPaper);
+
+        strJSON = CommonUtils.replaceUnicodeStr(strJSON);
+        //生成文件流写入JSON文件
+        FileOutputStream outputStream = null;
+        try {
+            outputStream = new FileOutputStream(file);
+            byte b[] = strJSON.getBytes();
+            outputStream.write(b);
+            outputStream.flush();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            IOUtils.closeQuietly(outputStream);
+        }
+    }
+
+    @Override
+    public void exportPaperFiles(List<String> paperIds, String serviceName, String exportContentList, HttpServletResponse response, String loginName, String examType) throws Exception {
+        ExportPaperAbstractService exportPaperAbstractService = (ExportPaperAbstractService) SpringContextUtils.getBeanById("tjdxExportPaperService");
+        //根据试卷id查询所有试卷
+        List<Paper> papers = CommonUtils.toList(paperRepo.findAll(paperIds));
+        String zipFileName = loginName;
+        //创建压缩文件夹
+        File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
+        if (directory.exists()) {
+            deteleFolder(TEMP_FILE_EXP, zipFileName);
+        }
+        directory.mkdirs();
+        //下载试卷
+        if (exportContentList.indexOf(ExamFileType.PAPER.name()) > -1) {
+            for (Paper paper : papers) {
+                exportPaperAbstractService.downloadPaper(paper.getId(), zipFileName, examType);
+            }
+        }
+        //下载答案
+        if (exportContentList.indexOf(ExamFileType.ANSWER.name()) > -1) {
+            for (Paper paper : papers) {
+                exportPaperAbstractService.downloadPaperAnswer(paper.getId(), zipFileName);
+            }
+        }
+        //下载机考数据包
+        if (exportContentList.indexOf(ExamFileType.COMPUTERTEST_PACKAGE.name()) > -1) {
+            int i = 1;
+            for (Paper paper : papers) {
+                //创建json文件夹
+                String jsonDir = TEMP_FILE_EXP + File.separator + zipFileName + File.separator + "json";
+                File jsonDirectory = new File(jsonDir);
+                if (!jsonDirectory.exists()) {
+                    jsonDirectory.mkdirs();
+                }
+                ComputerTestPaper computerTestPaper = buildComputerTestPapers(paper);
+                makeComputerTestPaperToJsonFile(paper.getCourse().getCode(), computerTestPaper, jsonDir);
+                //将文件夹打包成zip压缩包放在docxExport下
+                FileDisposeUtil.fileToZip(jsonDir, TEMP_FILE_EXP + File.separator + zipFileName, paper.getCourse().getCode() + "_" + paper.getName());
+                //删除json文件夹
+                File ComputerTestPaperfoler = new File(jsonDir);
+                if (ComputerTestPaperfoler.exists()) {
+                    FileUtils.deleteQuietly(ComputerTestPaperfoler);
+                }
+            }
+        }
+        String nameString = System.currentTimeMillis() + "";
+        FileDisposeUtil.fileToZip(TEMP_FILE_EXP + File.separator + zipFileName, TEMP_FILE_EXP, nameString);
+        FileDisposeUtil.downloadFile(nameString + ".zip", TEMP_FILE_EXP + File.separator + nameString + ".zip", response);
+        deteleFolder(TEMP_FILE_EXP, zipFileName);
+    }
+
+    @Override
+    public void downQuestionDistribute(String courseNo, HttpServletResponse response) throws IOException {
+        //1.生成导出Excle的list集合
+        List<QuestionDistributeDto> questionDistributeDtos = new ArrayList<QuestionDistributeDto>();
+        //2.根据课程code查询课程属性集合
+        List<CourseProperty> courseProperties = coursePropertyRepo.findByCourseCodeAndEnable(courseNo, true);
+        //3.遍历课程属性集合,根据课程属性查询一级
+        if (courseProperties != null && courseProperties.size() > 0) {
+            for (CourseProperty courseProperty : courseProperties) {
+                List<Property> parentProperties = propertyService.findPropertyParents(courseProperty.getId(), courseProperty.getOrgId());
+                if (parentProperties != null && parentProperties.size() > 0) {
+                    for (Property parentProperty : parentProperties) {
+                        List<Property> sonProperties = propertyService.findPropertySons(parentProperty.getId());
+                        if (sonProperties != null && sonProperties.size() > 0) {
+                            for (Property sonProperty : sonProperties) {
+                                //单选题集合
+                                List<Question> sinList = questionList(courseNo, courseProperty, QuesStructType.SINGLE_ANSWER_QUESTION, parentProperty, sonProperty);
+                                //多选题集合
+                                List<Question> mulList = questionList(courseNo, courseProperty, QuesStructType.MULTIPLE_ANSWER_QUESTION, parentProperty, sonProperty);
+                                //判断题集合
+                                List<Question> bolList = questionList(courseNo, courseProperty, QuesStructType.BOOL_ANSWER_QUESTION, parentProperty, sonProperty);
+                                //计算所有题型数量
+                                Map<Long, Long> map = countQuesType(sinList, mulList, bolList);
+                                QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(courseProperty.getName(), parentProperty.getName(), sonProperty.getName(), map);
+                                questionDistributeDtos.add(questionDistributeDto);
+                            }
+                        } else {
+                            //一级属性不为空,二级属性为空
+                            //单选题集合
+                            List<Question> sinList = questionList(courseNo, courseProperty, QuesStructType.SINGLE_ANSWER_QUESTION, parentProperty, null);
+                            //多选题集合
+                            List<Question> mulList = questionList(courseNo, courseProperty, QuesStructType.MULTIPLE_ANSWER_QUESTION, parentProperty, null);
+                            //判断题集合
+                            List<Question> bolList = questionList(courseNo, courseProperty, QuesStructType.BOOL_ANSWER_QUESTION, parentProperty, null);
+                            //计算所有题型数量
+                            Map<Long, Long> map = countQuesType(sinList, mulList, bolList);
+                            QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(courseProperty.getName(), parentProperty.getName(), null, map);
+                            questionDistributeDtos.add(questionDistributeDto);
+                        }
+                    }
+                } else {
+                    //一级属性为空
+                    QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(courseProperty.getName(), null, null, null);
+                    questionDistributeDtos.add(questionDistributeDto);
+                }
+            }
+        }
+        //生成Excel导出
+        writeExcel(questionDistributeDtos, 21, courseNo, response);
+    }
+
+    /**
+     * 数据源		questionDistributeDtos
+     * Excel列数	cloumnCount
+     *
+     * @param questionDistributeDtos
+     * @param cloumnCount
+     * @throws IOException
+     */
+    private void writeExcel(List<QuestionDistributeDto> questionDistributeDtos, int cloumnCount, String courseNo, HttpServletResponse response) throws IOException {
+        //读取Excel模板
+        InputStream in = this.getClass().getResourceAsStream("/quesDistinct.xlsx");
+        Workbook workBook = new XSSFWorkbook(in);
+        //System.out.println(workBook.getAllNames());
+        //获取第一个工作页
+        Sheet sheet = workBook.getSheetAt(0);
+        System.out.println(sheet.getSheetName());
+        //往Excel中写入数据,从第5行开始
+        for (int i = 0; i < questionDistributeDtos.size(); i++) {
+            //创建一行:从第五行开始,跳过表头
+            Row row = sheet.createRow(i + 4);
+            //获取这行的记录
+            QuestionDistributeDto questionDistributeDto = questionDistributeDtos.get(i);
+            //每列赋值
+            row.createCell(0).setCellValue(questionDistributeDto.getCoursePropertyName());
+            row.createCell(1).setCellValue(questionDistributeDto.getFirstPropertyName());
+            row.createCell(2).setCellValue(questionDistributeDto.getSecondPropertyName());
+            Map<Long, Long> map = questionDistributeDto.getMap();
+            if (map == null) {
+                for (int j = 0; j < 18; j++) {
+                    row.createCell(j + 3).setCellValue(0);
+                }
+            } else {
+                int j = 3;
+                for (Long key : map.keySet()) {
+                    row.createCell(j).setCellValue(map.get(key));
+                    j++;
+                }
+            }
+        }
+        File file = new File(TEMP_FILE_EXP + File.separator + "试题分布.xlsx");
+        OutputStream out = new FileOutputStream(file);
+        workBook.write(out);
+        out.close();
+        FileDisposeUtil.downloadFile(courseNo + "试题分布.xlsx", TEMP_FILE_EXP + File.separator + "试题分布.xlsx", response);
+        FileUtils.deleteQuietly(file);
     }
 
-	@Override
-	public  void exportPaperFiles(List<String> paperIds,String serviceName,String exportContentList, HttpServletResponse response,String loginName,String examType) throws Exception {
-		ExportPaperAbstractService exportPaperAbstractService = (ExportPaperAbstractService) SpringContextUtils.getBeanById("tjdxExportPaperService");
-		//根据试卷id查询所有试卷
-		List<Paper> papers = CommonUtils.toList(paperRepo.findAll(paperIds));
-		String zipFileName = loginName;
-		//创建压缩文件夹
-		File directory = new File(TEMP_FILE_EXP + File.separator + zipFileName);
-		if(directory.exists()){
-			deteleFolder(TEMP_FILE_EXP,zipFileName);
-		}
-		directory.mkdirs();
-		//下载试卷
-		if(exportContentList.indexOf("PAPER")>-1){
-			for(Paper paper:papers){
-				exportPaperAbstractService.downloadPaper(paper.getId(),zipFileName,examType);
-			}
-		}
-		//下载答案
-		if(exportContentList.indexOf("ANSWER")>-1){
-			for(Paper paper:papers){
-				exportPaperAbstractService.downloadPaperAnswer(paper.getId(),zipFileName);
-			}
-		}
-		//下载机考数据包
-		if(exportContentList.indexOf("COMPUTERTEST_PACKAGE")>-1){
-			int i = 1;
-			for(Paper paper:papers){
-				//创建json文件夹
-				String jsonDir = TEMP_FILE_EXP + File.separator + zipFileName + File.separator + "json";
-				File jsonDirectory = new File(jsonDir);
-				if(!jsonDirectory.exists()){
-					jsonDirectory.mkdirs();
-				}
-				ComputerTestPaper computerTestPaper = buildComputerTestPapers(paper);
-				makeComputerTestPaperToJsonFile(paper.getCourse().getCode(),computerTestPaper,jsonDir);
-				//将文件夹打包成zip压缩包放在docxExport下
-				FileDisposeUtil.fileToZip(jsonDir,TEMP_FILE_EXP+File.separator+zipFileName,paper.getCourse().getCode()+"_"+paper.getName());
-				//删除json文件夹
-				File ComputerTestPaperfoler = new File(jsonDir);
-				if(ComputerTestPaperfoler.exists()){
-					FileUtils.deleteQuietly(ComputerTestPaperfoler);
-				}
-			}
-		}
-		String nameString = System.currentTimeMillis()+"";
-		FileDisposeUtil.fileToZip(TEMP_FILE_EXP+File.separator+zipFileName,TEMP_FILE_EXP,nameString);
-		FileDisposeUtil.downloadFile(nameString +".zip", TEMP_FILE_EXP+File.separator+nameString+".zip",response);
-		deteleFolder(TEMP_FILE_EXP,zipFileName);
-	}
-
-	@Override
-	public void downQuestionDistribute(String courseNo,HttpServletResponse response) throws IOException {
-		//1.生成导出Excle的list集合
-		List<QuestionDistributeDto> questionDistributeDtos = new ArrayList<QuestionDistributeDto>();
-		//2.根据课程code查询课程属性集合
-		List<CourseProperty> courseProperties = coursePropertyRepo.findByCourseCodeAndEnable(courseNo, true);
-		//3.遍历课程属性集合,根据课程属性查询一级
-		if(courseProperties != null && courseProperties.size()>0){
-			for(CourseProperty courseProperty:courseProperties){
-				List<Property> parentProperties = propertyService.findPropertyParents(courseProperty.getId(), courseProperty.getOrgId());
-				if(parentProperties != null && parentProperties.size()>0){
-					for(Property parentProperty:parentProperties){
-						List<Property> sonProperties = propertyService.findPropertySons(parentProperty.getId());
-						if(sonProperties != null && sonProperties.size()>0){
-							for(Property sonProperty:sonProperties){
-								//单选题集合
-								List<Question> sinList = questionList(courseNo, courseProperty, QuesStructType.SINGLE_ANSWER_QUESTION, parentProperty, sonProperty);
-								//多选题集合
-								List<Question> mulList = questionList(courseNo, courseProperty, QuesStructType.MULTIPLE_ANSWER_QUESTION, parentProperty, sonProperty);
-								//判断题集合
-								List<Question> bolList = questionList(courseNo, courseProperty, QuesStructType.BOOL_ANSWER_QUESTION, parentProperty, sonProperty);
-								//计算所有题型数量
-								Map<Long,Long> map = countQuesType(sinList,mulList,bolList);
-								QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(courseProperty.getName(),parentProperty.getName(),sonProperty.getName(),map);
-								questionDistributeDtos.add(questionDistributeDto);
-							}
-						}else {
-							//一级属性不为空,二级属性为空
-							//单选题集合
-							List<Question> sinList = questionList(courseNo, courseProperty, QuesStructType.SINGLE_ANSWER_QUESTION, parentProperty, null);
-							//多选题集合
-							List<Question> mulList = questionList(courseNo, courseProperty, QuesStructType.MULTIPLE_ANSWER_QUESTION, parentProperty, null);
-							//判断题集合
-							List<Question> bolList = questionList(courseNo, courseProperty, QuesStructType.BOOL_ANSWER_QUESTION, parentProperty, null);
-							//计算所有题型数量
-							Map<Long,Long> map = countQuesType(sinList,mulList,bolList);
-							QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(courseProperty.getName(),parentProperty.getName(),null,map);
-							questionDistributeDtos.add(questionDistributeDto);
-						}
-					}
-				}else {
-					//一级属性为空
-					QuestionDistributeDto questionDistributeDto = new QuestionDistributeDto(courseProperty.getName(),null,null,null);
-					questionDistributeDtos.add(questionDistributeDto);
-				}
-			}
-		}
-		//生成Excel导出
-		writeExcel(questionDistributeDtos,21,courseNo,response);
-	}
-	
-	/**
-	 * 数据源		questionDistributeDtos
-	 * Excel列数	cloumnCount
-	 * @param questionDistributeDtos
-	 * @param cloumnCount
-	 * @throws IOException 
-	 */
-	private void writeExcel(List<QuestionDistributeDto> questionDistributeDtos,int cloumnCount,String courseNo,HttpServletResponse response) throws IOException {
-		//读取Excel模板
-		InputStream in = this.getClass().getResourceAsStream("/quesDistinct.xlsx");
-		Workbook workBook = new XSSFWorkbook(in);
-		//System.out.println(workBook.getAllNames());
-		//获取第一个工作页
-		Sheet sheet = workBook.getSheetAt(0);
-		System.out.println(sheet.getSheetName());
-		//往Excel中写入数据,从第5行开始
-		for(int i=0;i<questionDistributeDtos.size();i++){
-			//创建一行:从第五行开始,跳过表头
-			Row row = sheet.createRow(i+4);
-			//获取这行的记录
-			QuestionDistributeDto questionDistributeDto = questionDistributeDtos.get(i);
-			//每列赋值
-			row.createCell(0).setCellValue(questionDistributeDto.getCoursePropertyName());
-			row.createCell(1).setCellValue(questionDistributeDto.getFirstPropertyName());
-			row.createCell(2).setCellValue(questionDistributeDto.getSecondPropertyName());
-			Map<Long,Long> map = questionDistributeDto.getMap();
-			if(map == null){
-				for(int j=0;j<18;j++){
-					row.createCell(j+3).setCellValue(0);
-				}
-			}else {
-				int j = 3;
-				for(Long key:map.keySet()){
-					row.createCell(j).setCellValue(map.get(key));
-					j++;
-				}
-			}
-		}
-		File file = new File(TEMP_FILE_EXP + File.separator + "试题分布.xlsx");
-		OutputStream out = new FileOutputStream(file);
-		workBook.write(out);
-		out.close();
-		FileDisposeUtil.downloadFile(courseNo+"试题分布.xlsx", TEMP_FILE_EXP + File.separator + "试题分布.xlsx",response);
-		FileUtils.deleteQuietly(file);
-	}
-
-	private Map<Long, Long> countQuesType(List<Question> sinList,List<Question> mulList, List<Question> bolList) {
-		Map<Long,Long> map = new TreeMap<Long, Long>();
-		map = buildMap(sinList, map, 1);
-		map = buildMap(mulList, map, 2);
-		map = buildMap(bolList, map, 3);
-		//给map的键排序
-		Map<Long, Long> resultMap = sortMapByKey(map);
-		return resultMap;
-	}
-
-	private Map<Long, Long> sortMapByKey(Map<Long, Long> map) {
-		if (map == null || map.isEmpty()) {
+    private Map<Long, Long> countQuesType(List<Question> sinList, List<Question> mulList, List<Question> bolList) {
+        Map<Long, Long> map = new TreeMap<Long, Long>();
+        map = buildMap(sinList, map, 1);
+        map = buildMap(mulList, map, 2);
+        map = buildMap(bolList, map, 3);
+        //给map的键排序
+        Map<Long, Long> resultMap = sortMapByKey(map);
+        return resultMap;
+    }
+
+    private Map<Long, Long> sortMapByKey(Map<Long, Long> map) {
+        if (map == null || map.isEmpty()) {
             return null;
         }
-		Map<Long, Long> sortMap = new TreeMap<Long, Long>(new Comparator<Long>() {
-			public int compare(Long l1,Long l2){
-				return l1.compareTo(l2);
-			}
-		});
-		sortMap.putAll(map);
-		return sortMap;
-	}
-
-	private Map<Long, Long> buildMap(List<Question> quesList,Map<Long, Long> map,int questionType) {
-		//初始化map
-		for(int i=1;i<7;i++){
-			if(i<4){
-				map.put((long) (questionType*100+i), 0L);
-			}else {
-				map.put((long) (questionType*100+10+i-3), 0L);
-			}
-		}
-		for(Question question:quesList){
-			if(question.getPublicity()){
-				//公开
-				if(question.getDifficulty() !=null && question.getDifficulty().equals("难") || question.getDifficultyDegree()<0.4 && question.getDifficultyDegree()>0){
-					map = buildMapSum(questionType*100+1,map);
-				}else if(question.getDifficulty() !=null && question.getDifficulty().equals("中") || question.getDifficultyDegree()<0.8 && question.getDifficultyDegree()>0.3) {
-					map = buildMapSum(questionType*100+2,map);
-				}else{
-					map = buildMapSum(questionType*100+3,map);
-				}
-			}else {
-				//非公开
-				if(question.getDifficulty() !=null && question.getDifficulty().equals("难") || question.getDifficultyDegree()<0.4 && question.getDifficultyDegree()>0){
-					map = buildMapSum(questionType*100+11,map);
-				}else if(question.getDifficulty() !=null && question.getDifficulty().equals("中") || question.getDifficultyDegree()<0.8 && question.getDifficultyDegree()>0.3){
-					map = buildMapSum(questionType*100+12,map);
-				}else{
-					map = buildMapSum(questionType*100+13,map);
-				}
-			}
-		}
-		return map;
-	}
-	
-	private Map<Long, Long> buildMapSum(long key, Map<Long, Long> map) {
-		Long sum = map.get(key);
-		map.put(key, sum+1);
-		return map;
-	}
-
-	public List<Question> questionList(String courseNo,CourseProperty courseProperty,QuesStructType quesStructType,Property parentProperty,Property sonProperty){
-		Query query = new Query();
-		query.addCriteria(Criteria.where("orgId").is(courseProperty.getOrgId().toString()));
-		query.addCriteria(Criteria.where("course.enable").is("true"));
-		query.addCriteria(Criteria.where("course.code").is(courseNo));
-		query.addCriteria(Criteria.where("questionType").is(quesStructType.name()));
-		query.addCriteria(Criteria.where("quesProperties.coursePropertyName").is(courseProperty.getName()));
-		//二级属性不为空,那么一级属性也不为空
-        if(sonProperty != null && sonProperty.getId() != null){
-        	query.addCriteria(Criteria.where("quesProperties").elemMatch(Criteria.where("firstProperty.id").is(Long.valueOf(parentProperty.getId())).and("secondProperty.id").is(Long.valueOf(sonProperty.getId()))));
-        }else {
-        	if(parentProperty != null && parentProperty.getId() != null){
-            	query.addCriteria(Criteria.where("quesProperties").elemMatch(Criteria.where("firstProperty.id").is(Long.valueOf(parentProperty.getId()))));
+        Map<Long, Long> sortMap = new TreeMap<Long, Long>(new Comparator<Long>() {
+            public int compare(Long l1, Long l2) {
+                return l1.compareTo(l2);
+            }
+        });
+        sortMap.putAll(map);
+        return sortMap;
+    }
+
+    private Map<Long, Long> buildMap(List<Question> quesList, Map<Long, Long> map, int questionType) {
+        //初始化map
+        for (int i = 1; i < 7; i++) {
+            if (i < 4) {
+                map.put((long) (questionType * 100 + i), 0L);
+            } else {
+                map.put((long) (questionType * 100 + 10 + i - 3), 0L);
+            }
+        }
+        for (Question question : quesList) {
+            if (question.getPublicity()) {
+                //公开
+                if (question.getDifficulty() != null && question.getDifficulty().equals("难") || question.getDifficultyDegree() < 0.4 && question.getDifficultyDegree() > 0) {
+                    map = buildMapSum(questionType * 100 + 1, map);
+                } else if (question.getDifficulty() != null && question.getDifficulty().equals("中") || question.getDifficultyDegree() < 0.8 && question.getDifficultyDegree() > 0.3) {
+                    map = buildMapSum(questionType * 100 + 2, map);
+                } else {
+                    map = buildMapSum(questionType * 100 + 3, map);
+                }
+            } else {
+                //非公开
+                if (question.getDifficulty() != null && question.getDifficulty().equals("难") || question.getDifficultyDegree() < 0.4 && question.getDifficultyDegree() > 0) {
+                    map = buildMapSum(questionType * 100 + 11, map);
+                } else if (question.getDifficulty() != null && question.getDifficulty().equals("中") || question.getDifficultyDegree() < 0.8 && question.getDifficultyDegree() > 0.3) {
+                    map = buildMapSum(questionType * 100 + 12, map);
+                } else {
+                    map = buildMapSum(questionType * 100 + 13, map);
+                }
+            }
+        }
+        return map;
+    }
+
+    private Map<Long, Long> buildMapSum(long key, Map<Long, Long> map) {
+        Long sum = map.get(key);
+        map.put(key, sum + 1);
+        return map;
+    }
+
+    public List<Question> questionList(String courseNo, CourseProperty courseProperty, QuesStructType quesStructType, Property parentProperty, Property sonProperty) {
+        Query query = new Query();
+        query.addCriteria(Criteria.where("orgId").is(courseProperty.getOrgId().toString()));
+        query.addCriteria(Criteria.where("course.enable").is("true"));
+        query.addCriteria(Criteria.where("course.code").is(courseNo));
+        query.addCriteria(Criteria.where("questionType").is(quesStructType.name()));
+        query.addCriteria(Criteria.where("quesProperties.coursePropertyName").is(courseProperty.getName()));
+        //二级属性不为空,那么一级属性也不为空
+        if (sonProperty != null && sonProperty.getId() != null) {
+            query.addCriteria(Criteria.where("quesProperties").elemMatch(Criteria.where("firstProperty.id").is(Long.valueOf(parentProperty.getId())).and("secondProperty.id").is(Long.valueOf(sonProperty.getId()))));
+        } else {
+            if (parentProperty != null && parentProperty.getId() != null) {
+                query.addCriteria(Criteria.where("quesProperties").elemMatch(Criteria.where("firstProperty.id").is(Long.valueOf(parentProperty.getId()))));
             }
         }
         List<Question> questionList = this.mongoTemplate.find(query, Question.class);
-		return questionList;
-	}
-	
-	
-	public static void main(String[] args) {
-		System.out.println("a");
-		Map<Long, Long> map = new HashMap<Long, Long>();
-		map.put(1l, 1l);
-		map.put(1l, 2l);
-		System.out.println(map.get(1l));
-	}
+        return questionList;
+    }
+
+
+    public static void main(String[] args) {
+        System.out.println("a");
+        Map<Long, Long> map = new HashMap<Long, Long>();
+        map.put(1l, 1l);
+        map.put(1l, 2l);
+        System.out.println(map.get(1l));
+    }
 }

+ 462 - 454
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/impl/ExtractConfigFileServiceImpl.java

@@ -1,21 +1,28 @@
 package cn.com.qmth.examcloud.core.questions.service.impl;
 
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.servlet.http.HttpServletResponse;
-
+import cn.com.qmth.examcloud.common.dto.core.ExamCourseDto;
+import cn.com.qmth.examcloud.commons.base.util.excel.ExcelWriter;
+import cn.com.qmth.examcloud.commons.web.security.bean.User;
+import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
+import cn.com.qmth.examcloud.core.questions.base.FileDisposeUtil;
 import cn.com.qmth.examcloud.core.questions.base.ImageUtils;
+import cn.com.qmth.examcloud.core.questions.base.SpringContextUtils;
+import cn.com.qmth.examcloud.core.questions.base.enums.ExamFileType;
+import cn.com.qmth.examcloud.core.questions.base.enums.ExportType;
+import cn.com.qmth.examcloud.core.questions.base.enums.ExportWay;
+import cn.com.qmth.examcloud.core.questions.base.word.DocxProcessUtil;
+import cn.com.qmth.examcloud.core.questions.dao.ExportServiceManageRepo;
+import cn.com.qmth.examcloud.core.questions.dao.ExtractConfigRepo;
+import cn.com.qmth.examcloud.core.questions.dao.PaperDetailUnitRepo;
+import cn.com.qmth.examcloud.core.questions.dao.PaperRepo;
+import cn.com.qmth.examcloud.core.questions.dao.entity.*;
+import cn.com.qmth.examcloud.core.questions.service.*;
+import cn.com.qmth.examcloud.core.questions.service.bean.dto.*;
+import cn.com.qmth.examcloud.core.questions.service.converter.PrintExamPaperService;
+import cn.com.qmth.examcloud.core.questions.service.export.ExportPaperAbstractService;
+import cn.com.qmth.examcloud.core.questions.service.export.InitPaperExpService;
+import cn.com.qmth.examcloud.core.questions.service.rpc.ExamCourseClient;
 import main.java.com.UpYun;
-
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.docx4j.Docx4J;
@@ -26,469 +33,470 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
-import cn.com.qmth.examcloud.common.dto.core.ExamCourseDto;
-import cn.com.qmth.examcloud.commons.web.security.bean.User;
-import cn.com.qmth.examcloud.commons.web.security.entity.AccessUser;
-import cn.com.qmth.examcloud.commons.base.util.excel.ExcelWriter;
-import cn.com.qmth.examcloud.core.questions.dao.ExportServiceManageRepo;
-import cn.com.qmth.examcloud.core.questions.dao.ExtractConfigRepo;
-import cn.com.qmth.examcloud.core.questions.dao.PaperDetailUnitRepo;
-import cn.com.qmth.examcloud.core.questions.dao.PaperRepo;
-import cn.com.qmth.examcloud.core.questions.service.bean.dto.ExportPaperInfoModel;
-import cn.com.qmth.examcloud.core.questions.service.bean.dto.ObjectiveQuestionStructure;
-import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailExp;
-import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailUnitExp;
-import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperExp;
-import cn.com.qmth.examcloud.core.questions.service.bean.dto.SubjectiveQuestionStructure;
-import cn.com.qmth.examcloud.core.questions.dao.entity.ExamFile;
-import cn.com.qmth.examcloud.core.questions.dao.entity.ExportServiceManage;
-import cn.com.qmth.examcloud.core.questions.dao.entity.ExportStructure;
-import cn.com.qmth.examcloud.core.questions.dao.entity.ExtractConfig;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Paper;
-import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetailUnit;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuestionTypeNum;
-import cn.com.qmth.examcloud.core.questions.service.rpc.ExamCourseClient;
-import cn.com.qmth.examcloud.core.questions.service.ExamFileService;
-import cn.com.qmth.examcloud.core.questions.service.ExportStructureService;
-import cn.com.qmth.examcloud.core.questions.service.ExtractConfigFileService;
-import cn.com.qmth.examcloud.core.questions.service.ExtractConfigService;
-import cn.com.qmth.examcloud.core.questions.service.export.ExportPaperAbstractService;
-import cn.com.qmth.examcloud.core.questions.service.export.InitPaperExpService;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
-import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
-import cn.com.qmth.examcloud.core.questions.dao.entity.QuestionAudio;
-import cn.com.qmth.examcloud.core.questions.service.QuestionAudioService;
-import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
-import cn.com.qmth.examcloud.core.questions.base.FileDisposeUtil;
-import cn.com.qmth.examcloud.core.questions.base.SpringContextUtils;
-import cn.com.qmth.examcloud.core.questions.base.enums.ExamFileType;
-import cn.com.qmth.examcloud.core.questions.base.enums.ExportType;
-import cn.com.qmth.examcloud.core.questions.base.enums.ExportWay;
-import cn.com.qmth.examcloud.core.questions.base.word.DocxProcessUtil;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.*;
+import java.util.Map.Entry;
 
 /**
- * @author  	chenken
- * @date    	2017年7月31日 下午6:03:46
- * @company 	QMTH
+ * @author chenken
+ * @date 2017年7月31日 下午6:03:46
+ * @company QMTH
  * @description ExtractConfigFileServiceImpl.java
  */
 @Service("extractConfigFileService")
 public class ExtractConfigFileServiceImpl implements ExtractConfigFileService {
-	
-	private static final Logger logger = LoggerFactory.getLogger(ExtractConfigFileServiceImpl.class);
-	
-	public static final String TEMP_FILE_EXP = "docxExport/";
-	
-	public static final String TEMP_FILE_NAME = "_考试说明.docx";
-	
+
+    private static final Logger logger = LoggerFactory.getLogger(ExtractConfigFileServiceImpl.class);
+
+    public static final String TEMP_FILE_EXP = "docxExport/";
+
+    public static final String TEMP_FILE_NAME = "_考试说明.docx";
+
     @Autowired
     private ExamCourseClient examCourseClient;
-    
+
     @Autowired
     private ExportStructureService exportStructureService;
-    
+
     @Autowired
     private ExtractConfigService extractConfigService;
-    
+
     @Autowired
     private ExamFileService examFileService;
-    
+
     @Autowired
     private ExportServiceManageRepo exportServiceManageRepo;
-    
+
     @Autowired
     private ExtractConfigRepo extractConfigRepo;
-    
+
     @Autowired
-	private QuestionAudioService questionAudioService;
-    
+    private QuestionAudioService questionAudioService;
+
     @Autowired
-	private PaperRepo paperRepo;
-    
+    private PaperRepo paperRepo;
+
     @Autowired
     private PaperDetailUnitRepo paperDetailUnitRepo;
-    
+
     @Autowired
     private InitPaperExpService initPaperExpService;
-    
-	@Value("${upyun.downloadUrl}")
-	protected String downloadUrl;
-	
-	@Value("${upyun.downloadDirectory}")
-	private String downloadDirectory;
-	
-	@Value("${upyun.zipDirectory}")
-	private String zipDirectory;
-	
-	@Value("${upyun.bucketName}")
-	protected String bucketName;
-	
-	@Value("${upyun.userName}")
-	protected String userName;
-	
-	@Value("${upyun.password}")
-	protected String password;
-	
-	@Override
-	public void saveExtractConfigAndBuildPaperFile(ExtractConfig extractConfig,Integer isbuildFile,User user) throws Exception {
-		//查询试卷导出设置
-		ExportStructure exportStructure = null;
-		if(isbuildFile==1){
-			exportStructure = exportStructureService.findStructureByExamId(extractConfig.getExamId()+"");
-		}
-		//生成试卷
-		Map<String, String> finishedPaperIdMap = extractConfigService.saveExtractConfig(extractConfig,user);
-    	if(isbuildFile==1){
-    		//删除原有试卷文件
-        	ExamFile examFile = new ExamFile();
-        	examFile.setExamId(extractConfig.getExamId()+"");
-        	examFile.setCourseId(extractConfig.getCourseCode());
-        	examFile.setOrgId(extractConfig.getOrgId());
-        	examFileService.deleteExamFile(examFile);
-    		//生成并上传新的试卷文件
-    		Set<Entry<String,String>> entrySet = finishedPaperIdMap.entrySet();
-    		Iterator<Entry<String,String>> iterator = entrySet.iterator();
-    		while(iterator.hasNext()){
-    			Entry<String,String> entry = iterator.next();
-    			String paperId = entry.getValue();
-    			uploadPaperFile(extractConfig,paperId,exportStructure,user);
-    		}
-    	}
-	}
-	
-	/**
-	 * 生成并上传试卷文件
-	 * @param extractConfig
-	 * @param paperId
-	 * @param exportStructure
-	 * @param accessUser
-	 * @throws Exception
-	 */
-	private void uploadPaperFile(ExtractConfig extractConfig,String paperId,ExportStructure exportStructure,User user) throws Exception {
-		ExportServiceManage esm = exportServiceManageRepo.findByOrgName(user.getRootOrgName());
-		if(esm == null){
-			esm = exportServiceManageRepo.findByOrgName("陕西师范大学");
-		}
-    	ExportPaperAbstractService exportPaperAbstractService = (ExportPaperAbstractService) SpringContextUtils.getBeanById(esm.getExportServiceName());
-    	exportPaperAbstractService.uploadFile(extractConfig,paperId,exportStructure,user);
-	}
-	
+
+    @Autowired
+    private PrintExamPaperService printExamPaperService;
+
+    @Autowired
+    private ExportPaperService exportPaperService;
+
+    @Value("${upyun.downloadUrl}")
+    protected String downloadUrl;
+
+    @Value("${upyun.downloadDirectory}")
+    private String downloadDirectory;
+
+    @Value("${upyun.zipDirectory}")
+    private String zipDirectory;
+
+    @Value("${upyun.bucketName}")
+    protected String bucketName;
+
+    @Value("${upyun.userName}")
+    protected String userName;
+
+    @Value("${upyun.password}")
+    protected String password;
+
     @Override
-	public void exportExamPaperInfoCheck(ExportPaperInfoModel exportModel,HttpServletResponse response) throws Exception {
-    	ExportStructure exportStructure = exportStructureService.findStructureByExamId(exportModel.getExamId()+"");
-		//如果是批量导出
-		if(exportModel.getExportWay()==ExportWay.BATCH){
-			if(exportStructure==null){
-				exportStructure = new ExportStructure();
-				exportStructure.setExportType(ExportType.NORMAL);
-			}
-			//查询该考试下是否所有课程都制定了调卷规则和考试文件
-			checkAllCourseByExamId(exportModel.getExamId(),exportStructure.getExportType());
-		}
-	}
-
-	@Override
-	public void exportExamPaperInfo(ExportPaperInfoModel exportModel,HttpServletResponse response,String loginName,String orgName) throws Exception {
-		String tempDir = loginName + System.currentTimeMillis();
-		String downloadDir = downloadDirectory +"/"+ tempDir;
-		String downZipDir = zipDirectory +"/"+ tempDir;
-		//创建试卷和压缩文件 文件夹
-		FileDisposeUtil.createDirectory(downloadDir);
-		//创建压缩文件的文件夹
-		FileDisposeUtil.createDirectory(downZipDir);
-		ExportStructure exportStructure = exportStructureService.findStructureByExamId(exportModel.getExamId()+"");
-		if(exportStructure==null){
-			exportStructure = new ExportStructure();
-			exportStructure.setExportType(ExportType.NORMAL);
-		}
-		//如果是普通类型的批量导出  导出试卷结构
-		if(exportModel.getExportWay()==ExportWay.BATCH){
-			Map<String,String> paperIds = checkAllCourseByExamId(exportModel.getExamId(),exportStructure.getExportType());
-			if(exportStructure.getExportType()==ExportType.NORMAL){
-				if(paperIds.size()>0&&exportModel.getExportContentList().contains(ExamFileType.PAPER_STRUCTURE_OBJECTIVE.name())){
-					makePaperStructure(downloadDir,exportStructure.getExamName(),paperIds,exportStructure);
-				}
-			}
-		}
-		//根据条件获取到文件下载路径,下载文件到服务器的downloadDirectory文件夹
-		List<ExamFile> examFiles = examFileService.findExamFileListByExportPaperInfoModel(exportModel);
-		if(examFiles!=null&&examFiles.size()>0){
-			for(int i = 0;i<examFiles.size();i++){
-				ExamFile examFile = examFiles.get(i);
-				UpYun upyun = new UpYun(bucketName,userName,password);
-				File file = new File(downloadDir+File.separator+examFile.getFileName());
-				upyun.readFile(examFile.getFilePath(), file);
-				
-				if(examFile.getExamFileType()==ExamFileType.PAPER){
-					Long examId = Long.parseLong(exportModel.getExamId());
-					ExtractConfig extractConfig = extractConfigService.findConfig(new ExtractConfig(examId,examFile.getCourseId()));
-					Map<String,String> finishedPaperIdMap = extractConfig.getFinishedPaperIdMap();
-					Set<Entry<String,String>> entrySet = finishedPaperIdMap.entrySet();
-					Iterator<Entry<String,String>> iterator = entrySet.iterator();
-					while(iterator.hasNext()){
-						Entry<String,String> entry = iterator.next();
-						String groupCode = entry.getKey();
-						String paperId = entry.getValue();
-						if(groupCode.equals(examFile.getGroupCode())){
-							downloadAudio(paperId,examFile,downloadDir,orgName);
-						}
-					}
-				}
-			}
-		}
-		//创建压缩文件名称
-		String zipFileName = exportModel.getExamId();
-		//将downloadDirectory文件夹压缩成zip文件,存放到zipDirectory文件夹中
-		FileDisposeUtil.fileToZip(downloadDir,downZipDir,zipFileName);
-		//下载zip文件到客户端
-		FileDisposeUtil.downloadFile(zipFileName+".zip",downZipDir+File.separator+zipFileName+".zip",response);
-		//删除文件夹
-		FileUtils.deleteQuietly(new File(downloadDir));
-		FileUtils.deleteQuietly(new File(downZipDir));
-	}
-	
-	/**
-	 * 下载试卷音频文件
-	 * @throws Exception 
-	 */
-	private void downloadAudio(String paperId,ExamFile examFile,String downloadDir,String orgName) throws Exception{
-		//Paper paper = paperRepo.findOne(paperId);
-		ExportServiceManage esm = exportServiceManageRepo.findByOrgName(orgName);
-		if(esm == null){
-			esm = exportServiceManageRepo.findByOrgName("陕西师范大学");
-		}
-    	ExportPaperAbstractService exportPaperAbstractService = (ExportPaperAbstractService) SpringContextUtils.getBeanById(esm.getExportServiceName());
-		PaperExp paperExp = exportPaperAbstractService.initPaperExp(paperId);
-		//下载考试说明
-		if(StringUtils.isNotBlank(paperExp.getExamRemark())){
-			downExamRemark(paperExp,downloadDir,examFile);
-		}
-		//取到所有大题
-		List<PaperDetailExp> paperDetailExps = paperExp.getPaperDetails();
-		if(paperDetailExps != null && paperDetailExps.size()>0){
-			for(PaperDetailExp paperDetailExp:paperDetailExps){
-				//取到所有小题
-				List<PaperDetailUnitExp> paperDetailUnitExps = paperDetailExp.getPaperDetailUnits();
-				if(paperDetailUnitExps != null && paperDetailUnitExps.size()>0){
-					for(PaperDetailUnitExp unit:paperDetailUnitExps){
-						if(unit.getQuestion().getHasAudio()!=null&&unit.getQuestion().getHasAudio()){
-							List<QuestionAudio> questionAudios = questionAudioService.findQuestionAudiosByQuestionId(unit.getQuestion().getId());
-							for(QuestionAudio audio:questionAudios){
-								String audioFileName = examFile.getCourseName()
-														+"_"+examFile.getCourseId()
-														+"_试卷_"+examFile.getGroupCode()
-														+"_"+exportPaperAbstractService.getAudioFileName(audio,unit,paperDetailExp);
-								UpYun upyun = new UpYun(bucketName,userName,password);
-								File file = new File(downloadDir+File.separator+audioFileName);
-								upyun.readFile(audio.getFileUrl(), file);
-							}
-						}
-					}
-				}
-			}
-		}
-	}
-	
-	/**
-	 * 下载考试说明
-	 * @param paper
-	 * @param zipFileName
-	 * @throws Exception
-	 */
-	public void downExamRemark(PaperExp paperExp,String zipFileName,ExamFile examFile) throws Exception {
-		//1.考试说明html转成word
-		String title = "<p style=\"text-align:center\"><span style=\"font-size:26px\"><span style=\"font-family:宋体\">考&nbsp;试&nbsp;说&nbsp;明</span></span></p>";
-		WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
-		String html = title + ImageUtils.reSizeImg(paperExp.getExamRemark());
-		DocxProcessUtil.html2Docx(wordMLPackage, CommonUtils.formatHtml(html));
-		//2.导出考试说明word	
-		File file = new File(zipFileName+File.separator+paperExp.getName()+"_"+paperExp.getCourse().getName()+"_"+paperExp.getCourse().getCode()+"_"+examFile.getGroupCode()+TEMP_FILE_NAME);
-		Docx4J.save(wordMLPackage, file);
-	}
-	
-	/**
-	 * 计算取得音频文件名称
-	 * @param audio
-	 * @param unit
-	 * @return
-	 */
-	private String getAudioFileName(QuestionAudio audio,PaperDetailUnit unit){
-		String questionAudioId = audio.getId();
-		StringBuffer audioFileName = new StringBuffer(unit.getPaperDetail().getNumber()+"_"+unit.getNumber()+"_");
-		Question question = unit.getQuestion();
-		List<String> idvaluesBody = CommonUtils.getTagANames(question.getQuesBody());
-		if(idvaluesBody.contains(questionAudioId)){
-			audioFileName.append("1");//题干
-			audioFileName.append("_");
-			int index = idvaluesBody.indexOf(questionAudioId);
-			audioFileName.append(index+1);
-		}else{
-			List<QuesOption> options = question.getQuesOptions();
-			if(options!=null&&options.size()>0){
-				for(QuesOption option:options){
-					List<String> idvaluesOption = CommonUtils.getTagANames(option.getOptionBody());
-					if(idvaluesOption.contains(questionAudioId)){
-						audioFileName.append("2");//选项
-						audioFileName.append("_");
-						audioFileName.append(CommonUtils.getOptionNum(Integer.parseInt(option.getNumber())-1));
-						audioFileName.append("_");
-						int index = idvaluesOption.indexOf(questionAudioId);
-						audioFileName.append(index+1);
-						break;
-					}
-				}
-			}
-		}
-		audioFileName.append(".");
-		audioFileName.append(audio.getFileSuffixes());
-		return audioFileName.toString();
-	}
-	
-	/**
-	 * 查询该考试下是否所有课程都制定了调卷规则
-	 * @param examId
-	 */
-	private Map<String,String> checkAllCourseByExamId(String examId,ExportType exportType) {
-		Map<String,String> paperIdMap = new HashMap<String,String>();
-		List<ExamCourseDto> examCourseDtoList = examCourseClient.findExamCourseByExamId(examId);
-		for(ExamCourseDto examCourseDto:examCourseDtoList){
-			ExtractConfig condition = new ExtractConfig();
-			condition.setExamId(examCourseDto.getExamId());
-			condition.setCourseCode(examCourseDto.getCourseCode());
-			ExtractConfig extractConfig = extractConfigService.findConfig(condition);
-			if(extractConfig==null){
-				throw new RuntimeException("该考试下的课程“"+examCourseDto.getCourseName()+"”没有制定调卷规则,不能批量导出,请保存调卷规则生成文件");
-			}
-			if(extractConfig.getIfFinish()==null||extractConfig.getIfFinish()==0){
-				throw new RuntimeException("该考试下的课程“"+examCourseDto.getCourseName()+"”考试文件没有生成,不能批量导出,请保存调卷规则生成文件");
-			}
-			checkExamFileExists(examId,examCourseDto,exportType);
-			Map<String,String> finishedPaperIdMap = extractConfig.getFinishedPaperIdMap();
-			Set<Entry<String,String>> entry = finishedPaperIdMap.entrySet();
-			Iterator<Entry<String,String>> iterator = entry.iterator();
-			while(iterator.hasNext()){
-				Entry<String,String> next = iterator.next();
-				//paperId为key,paperType为value
-				paperIdMap.put(next.getValue(),next.getKey());
-			}
-		}
-		return paperIdMap;
-	}
-	
-	/**
-	 * 检查试卷文件是否存在
-	 * @param examId
-	 * @param examCourseDto
-	 */
-	private void checkExamFileExists(String examId,ExamCourseDto examCourseDto,ExportType exportType){
-		ExamFile examFileCondition = new ExamFile();
-		examFileCondition.setExamId(examId);
-		examFileCondition.setCourseId(examCourseDto.getCourseCode());
-		
-		List<ExamFile> examfiles = examFileService.findExamFileListByExamFile(examFileCondition);
-		
-		//检查是否都生成了试卷文件
-		boolean paperFlag = false;
-		if(exportType == ExportType.NORMAL){
-			for(ExamFile examFile:examfiles){
-				if(examFile.getExamFileType()==ExamFileType.PAPER){
-					paperFlag = true;
-				}
-			}
-		}else{
-			for(ExamFile examFile:examfiles){
-				if(examFile.getExamFileType()==ExamFileType.COMPUTERTEST_PACKAGE){
-					paperFlag = true;
-				}
-			}
-		}
-		
-		if(!paperFlag){
-			String message = exportType == ExportType.NORMAL?"考试文件":"机考数据包";
-			throw new RuntimeException("该考试下的课程“"+examCourseDto.getCourseName()+"”"+message+"没有生成,不能批量导出,请重新保存调卷规则生成");
-		}
-	}
-	
-	/**
-	 * 将该考试下的所有课程试卷的结构生成到一张Excel表中
-	 * @param examName
-	 * @param paperIds
-	 * @param exportStructure
-	 * @throws Exception
-	 */
-	private void makePaperStructure(String downloadDir,String examName,Map<String,String> paperIds,ExportStructure exportStructure) throws Exception{
-		logger.info("正在批量生成试卷结构...");
-		List<QuestionTypeNum> questionTypeNums = exportStructure.getQuestionTypeNums();
-		//客观题集合
-		List<ObjectiveQuestionStructure> objectiveQuestionStructureList = new ArrayList<ObjectiveQuestionStructure>();
-		//主观题集合
-		List<SubjectiveQuestionStructure> subjectiveQuestionStructureList = new ArrayList<SubjectiveQuestionStructure>();
-		
-		ExportServiceManage esm = exportServiceManageRepo.findByOrgName(exportStructure.getOrgName());
-		if(esm==null){
-			esm = exportServiceManageRepo.findByOrgName("陕西师范大学");
-		}
-    	ExportPaperAbstractService exportPaperAbstractService = (ExportPaperAbstractService) SpringContextUtils.getBeanById(esm.getExportServiceName());
-    	Set<Entry<String,String>> entrySet = paperIds.entrySet();
-		Iterator<Entry<String,String>> iterator = entrySet.iterator();
-		
-		while(iterator.hasNext()){
-			Entry<String,String> entry = iterator.next();
-			String paperId = entry.getKey();
-			String paperType = entry.getValue();
-			logger.info("初始化试卷:"+paperId);
-			PaperExp paperExp = initPaperExpService.initPaperExp(paperId);
-			logger.info("处理客观题...");
-			//添加客观题
-			List<PaperDetailExp> objectiveDetails = exportPaperAbstractService.getAllObjectiveDetails(paperExp);
-			//得到补齐后的客观题大题
-			List<PaperDetailExp> paperDetailExps = exportPaperAbstractService.fillObjectiveQuestions(objectiveDetails, questionTypeNums);
-			List<ObjectiveQuestionStructure> objectiveList = new ArrayList<ObjectiveQuestionStructure>();
-	    	for(PaperDetailExp paperDetailExp:paperDetailExps){
-	    		for(PaperDetailUnitExp unit:paperDetailExp.getPaperDetailUnits()){
-	    			objectiveList.add(new ObjectiveQuestionStructure(paperExp,paperDetailExp,unit,paperType));
-	    		}
-	    	}
-	    	objectiveQuestionStructureList.addAll(objectiveList);
-	    	logger.info("处理客观题完成");
-	    	//添加主观题
-	    	logger.info("处理主观题...");
-	    	List<PaperDetailExp> subjectiveDetails = exportPaperAbstractService.getAllSubjectiveDetails(paperExp);
-	    	List<SubjectiveQuestionStructure> subjectiveList = new ArrayList<SubjectiveQuestionStructure>();
-	    	for(PaperDetailExp paperDetailExp:subjectiveDetails){
-	    		for(PaperDetailUnitExp unit:paperDetailExp.getPaperDetailUnits()){
-	    			subjectiveList.add(new SubjectiveQuestionStructure(paperExp,paperDetailExp,unit,paperType));
-	    		}
-	    	}
-	    	subjectiveQuestionStructureList.addAll(subjectiveList);
-	    	logger.info("处理主观题完成");
-		}
-		
-		ExcelWriter objectiveExcelExporter = new ExcelWriter(ObjectiveQuestionStructure.class); 
-		String keguanFileName = examName+"_客观题.xlsx";
-    	FileOutputStream out1 = getFileOutputStream(downloadDir,keguanFileName);
-    	objectiveExcelExporter.write(keguanFileName,objectiveQuestionStructureList,out1);
-    	
-    	ExcelWriter subjectiveExcelExporter = new ExcelWriter(SubjectiveQuestionStructure.class); 
-    	String zhuguanFileName = examName+"_主观题.xlsx";
-    	FileOutputStream out2 = getFileOutputStream(downloadDir,zhuguanFileName);
-    	subjectiveExcelExporter.write(zhuguanFileName,subjectiveQuestionStructureList,out2);
-    	
-    	out1.close();
-    	out2.close();
-    	logger.info("批量生成试卷结构完成");
-	}
-	
-	private FileOutputStream getFileOutputStream(String downloadDir,String fileName) throws IOException{
-		File directory = new File(downloadDir);
-		if(!directory.exists()){
-			directory.mkdirs();
-		}
-		File file = new File(downloadDir+File.separator+fileName);
-		if(!file.exists()){
-			file.createNewFile();
-		}
-		return new FileOutputStream(file);
-	}
-	
+    public void saveExtractConfigAndBuildPaperFile(ExtractConfig extractConfig, Integer isbuildFile, User user) throws Exception {
+        //查询试卷导出设置
+        ExportStructure exportStructure = null;
+        if (isbuildFile == 1) {
+            exportStructure = exportStructureService.findStructureByExamId(extractConfig.getExamId() + "");
+        }
+        //生成试卷
+        Map<String, String> finishedPaperIdMap = extractConfigService.saveExtractConfig(extractConfig, user);
+        if (isbuildFile == 1) {
+            //删除原有试卷文件
+            ExamFile examFile = new ExamFile();
+            examFile.setExamId(extractConfig.getExamId() + "");
+            examFile.setCourseId(extractConfig.getCourseCode());
+            examFile.setOrgId(extractConfig.getOrgId());
+            examFileService.deleteExamFile(examFile);
+            //生成并上传新的试卷文件
+            Set<Entry<String, String>> entrySet = finishedPaperIdMap.entrySet();
+            Iterator<Entry<String, String>> iterator = entrySet.iterator();
+            while (iterator.hasNext()) {
+                Entry<String, String> entry = iterator.next();
+                String paperId = entry.getValue();
+                uploadPaperFile(extractConfig, paperId, exportStructure, user);
+            }
+        }
+    }
+
+    /**
+     * 生成并上传试卷文件
+     *
+     * @param extractConfig
+     * @param paperId
+     * @param exportStructure
+     * @param user
+     * @throws Exception
+     */
+    private void uploadPaperFile(ExtractConfig extractConfig, String paperId, ExportStructure exportStructure, User user) throws Exception {
+        ExportServiceManage esm = exportServiceManageRepo.findByOrgName(user.getRootOrgName());
+        if (esm == null) {
+            esm = exportServiceManageRepo.findByOrgName("陕西师范大学");
+        }
+        ExportPaperAbstractService exportPaperAbstractService = (ExportPaperAbstractService) SpringContextUtils.getBeanById(esm.getExportServiceName());
+        exportPaperAbstractService.uploadFile(extractConfig, paperId, exportStructure, user);
+    }
+
+    @Override
+    public void exportExamPaperInfoCheck(ExportPaperInfoModel exportModel, HttpServletResponse response) throws Exception {
+        ExportStructure exportStructure = exportStructureService.findStructureByExamId(exportModel.getExamId() + "");
+        //如果是批量导出
+        if (exportModel.getExportWay() == ExportWay.BATCH) {
+            if (exportStructure == null) {
+                exportStructure = new ExportStructure();
+                exportStructure.setExportType(ExportType.NORMAL);
+            }
+            //查询该考试下是否所有课程都制定了调卷规则和考试文件
+            checkAllCourseByExamId(exportModel.getExamId(), exportStructure.getExportType());
+        }
+    }
+
+    @Override
+    public void exportExamPaperInfo(ExportPaperInfoModel exportModel, HttpServletResponse response, String loginName, String orgName, String psw) throws Exception {
+        String tempDir = loginName + System.currentTimeMillis();
+        String downloadDir = downloadDirectory + "/" + tempDir;
+        String downZipDir = zipDirectory + "/" + tempDir;
+        //创建试卷和压缩文件 文件夹
+        FileDisposeUtil.createDirectory(downloadDir);
+        //创建压缩文件的文件夹
+        FileDisposeUtil.createDirectory(downZipDir);
+        ExportStructure exportStructure = exportStructureService.findStructureByExamId(exportModel.getExamId() + "");
+        if (exportStructure == null) {
+            exportStructure = new ExportStructure();
+            exportStructure.setExportType(ExportType.NORMAL);
+        }
+
+        //导出分布式印刷的数据包
+        if (exportModel.getExportContentList().contains(ExamFileType.PRINT_EXAM_PACKAGE.name())) {
+            ExtractConfig condition = new ExtractConfig();
+            condition.setExamId(Long.valueOf(exportModel.getExamId()));
+            condition.setCourseCode(exportModel.getCourseId());
+            //获取调卷规则
+            ExtractConfig extractConfig = extractConfigService.findConfig(condition);
+            if (extractConfig != null) {
+                List<Paper> papers = new ArrayList<>();
+                List<ExamPaper> examPapers = extractConfig.getExamPaperList();
+                if (examPapers != null && examPapers.size() > 0) {
+                    for (ExamPaper examPaper : examPapers) {
+                        papers.add(examPaper.getPaper());
+                    }
+                }
+                printExamPaperService.downloadPaper(papers, downloadDir, psw);
+            } else {
+                logger.info("exportPrintExamPaper fail, extractConfig is not exist!");
+            }
+        }
+
+        //如果是普通类型的批量导出  导出试卷结构
+        if (exportModel.getExportWay() == ExportWay.BATCH) {
+            Map<String, String> paperIds = checkAllCourseByExamId(exportModel.getExamId(), exportStructure.getExportType());
+            if (exportStructure.getExportType() == ExportType.NORMAL) {
+                if (paperIds.size() > 0 && exportModel.getExportContentList().contains(ExamFileType.PAPER_STRUCTURE_OBJECTIVE.name())) {
+                    makePaperStructure(downloadDir, exportStructure.getExamName(), paperIds, exportStructure);
+                }
+            }
+        }
+        //根据条件获取到文件下载路径,下载文件到服务器的downloadDirectory文件夹
+        List<ExamFile> examFiles = examFileService.findExamFileListByExportPaperInfoModel(exportModel);
+        if (examFiles != null && examFiles.size() > 0) {
+            for (int i = 0; i < examFiles.size(); i++) {
+                ExamFile examFile = examFiles.get(i);
+                UpYun upyun = new UpYun(bucketName, userName, password);
+                File file = new File(downloadDir + File.separator + examFile.getFileName());
+                upyun.readFile(examFile.getFilePath(), file);
+
+                if (examFile.getExamFileType() == ExamFileType.PAPER) {
+                    Long examId = Long.parseLong(exportModel.getExamId());
+                    ExtractConfig extractConfig = extractConfigService.findConfig(new ExtractConfig(examId, examFile.getCourseId()));
+                    Map<String, String> finishedPaperIdMap = extractConfig.getFinishedPaperIdMap();
+                    Set<Entry<String, String>> entrySet = finishedPaperIdMap.entrySet();
+                    Iterator<Entry<String, String>> iterator = entrySet.iterator();
+                    while (iterator.hasNext()) {
+                        Entry<String, String> entry = iterator.next();
+                        String groupCode = entry.getKey();
+                        String paperId = entry.getValue();
+                        if (groupCode.equals(examFile.getGroupCode())) {
+                            downloadAudio(paperId, examFile, downloadDir, orgName);
+                        }
+                    }
+                }
+            }
+        }
+        //创建压缩文件名称
+        String zipFileName = exportModel.getExamId();
+        //将downloadDirectory文件夹压缩成zip文件,存放到zipDirectory文件夹中
+        FileDisposeUtil.fileToZip(downloadDir, downZipDir, zipFileName);
+        //下载zip文件到客户端
+        FileDisposeUtil.downloadFile(zipFileName + ".zip", downZipDir + File.separator + zipFileName + ".zip", response);
+        //删除文件夹
+        FileUtils.deleteQuietly(new File(downloadDir));
+        FileUtils.deleteQuietly(new File(downZipDir));
+    }
+
+    /**
+     * 下载试卷音频文件
+     *
+     * @throws Exception
+     */
+    private void downloadAudio(String paperId, ExamFile examFile, String downloadDir, String orgName) throws Exception {
+        //Paper paper = paperRepo.findOne(paperId);
+        ExportServiceManage esm = exportServiceManageRepo.findByOrgName(orgName);
+        if (esm == null) {
+            esm = exportServiceManageRepo.findByOrgName("陕西师范大学");
+        }
+        ExportPaperAbstractService exportPaperAbstractService = (ExportPaperAbstractService) SpringContextUtils.getBeanById(esm.getExportServiceName());
+        PaperExp paperExp = exportPaperAbstractService.initPaperExp(paperId);
+        //下载考试说明
+        if (StringUtils.isNotBlank(paperExp.getExamRemark())) {
+            downExamRemark(paperExp, downloadDir, examFile);
+        }
+        //取到所有大题
+        List<PaperDetailExp> paperDetailExps = paperExp.getPaperDetails();
+        if (paperDetailExps != null && paperDetailExps.size() > 0) {
+            for (PaperDetailExp paperDetailExp : paperDetailExps) {
+                //取到所有小题
+                List<PaperDetailUnitExp> paperDetailUnitExps = paperDetailExp.getPaperDetailUnits();
+                if (paperDetailUnitExps != null && paperDetailUnitExps.size() > 0) {
+                    for (PaperDetailUnitExp unit : paperDetailUnitExps) {
+                        if (unit.getQuestion().getHasAudio() != null && unit.getQuestion().getHasAudio()) {
+                            List<QuestionAudio> questionAudios = questionAudioService.findQuestionAudiosByQuestionId(unit.getQuestion().getId());
+                            for (QuestionAudio audio : questionAudios) {
+                                String audioFileName = examFile.getCourseName()
+                                        + "_" + examFile.getCourseId()
+                                        + "_试卷_" + examFile.getGroupCode()
+                                        + "_" + exportPaperAbstractService.getAudioFileName(audio, unit, paperDetailExp);
+                                UpYun upyun = new UpYun(bucketName, userName, password);
+                                File file = new File(downloadDir + File.separator + audioFileName);
+                                upyun.readFile(audio.getFileUrl(), file);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 下载考试说明
+     *
+     * @param zipFileName
+     * @throws Exception
+     */
+    public void downExamRemark(PaperExp paperExp, String zipFileName, ExamFile examFile) throws Exception {
+        //1.考试说明html转成word
+        String title = "<p style=\"text-align:center\"><span style=\"font-size:26px\"><span style=\"font-family:宋体\">考&nbsp;试&nbsp;说&nbsp;明</span></span></p>";
+        WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
+        String html = title + ImageUtils.reSizeImg(paperExp.getExamRemark());
+        DocxProcessUtil.html2Docx(wordMLPackage, CommonUtils.formatHtml(html));
+        //2.导出考试说明word
+        File file = new File(zipFileName + File.separator + paperExp.getName() + "_" + paperExp.getCourse().getName() + "_" + paperExp.getCourse().getCode() + "_" + examFile.getGroupCode() + TEMP_FILE_NAME);
+        Docx4J.save(wordMLPackage, file);
+    }
+
+    /**
+     * 计算取得音频文件名称
+     *
+     * @param audio
+     * @param unit
+     * @return
+     */
+    private String getAudioFileName(QuestionAudio audio, PaperDetailUnit unit) {
+        String questionAudioId = audio.getId();
+        StringBuffer audioFileName = new StringBuffer(unit.getPaperDetail().getNumber() + "_" + unit.getNumber() + "_");
+        Question question = unit.getQuestion();
+        List<String> idvaluesBody = CommonUtils.getTagANames(question.getQuesBody());
+        if (idvaluesBody.contains(questionAudioId)) {
+            audioFileName.append("1");//题干
+            audioFileName.append("_");
+            int index = idvaluesBody.indexOf(questionAudioId);
+            audioFileName.append(index + 1);
+        } else {
+            List<QuesOption> options = question.getQuesOptions();
+            if (options != null && options.size() > 0) {
+                for (QuesOption option : options) {
+                    List<String> idvaluesOption = CommonUtils.getTagANames(option.getOptionBody());
+                    if (idvaluesOption.contains(questionAudioId)) {
+                        audioFileName.append("2");//选项
+                        audioFileName.append("_");
+                        audioFileName.append(CommonUtils.getOptionNum(Integer.parseInt(option.getNumber()) - 1));
+                        audioFileName.append("_");
+                        int index = idvaluesOption.indexOf(questionAudioId);
+                        audioFileName.append(index + 1);
+                        break;
+                    }
+                }
+            }
+        }
+        audioFileName.append(".");
+        audioFileName.append(audio.getFileSuffixes());
+        return audioFileName.toString();
+    }
+
+    /**
+     * 查询该考试下是否所有课程都制定了调卷规则
+     *
+     * @param examId
+     */
+    private Map<String, String> checkAllCourseByExamId(String examId, ExportType exportType) {
+        Map<String, String> paperIdMap = new HashMap<String, String>();
+        List<ExamCourseDto> examCourseDtoList = examCourseClient.findExamCourseByExamId(examId);
+        for (ExamCourseDto examCourseDto : examCourseDtoList) {
+            ExtractConfig condition = new ExtractConfig();
+            condition.setExamId(examCourseDto.getExamId());
+            condition.setCourseCode(examCourseDto.getCourseCode());
+            ExtractConfig extractConfig = extractConfigService.findConfig(condition);
+            if (extractConfig == null) {
+                throw new RuntimeException("该考试下的课程“" + examCourseDto.getCourseName() + "”没有制定调卷规则,不能批量导出,请保存调卷规则生成文件");
+            }
+            if (extractConfig.getIfFinish() == null || extractConfig.getIfFinish() == 0) {
+                throw new RuntimeException("该考试下的课程“" + examCourseDto.getCourseName() + "”考试文件没有生成,不能批量导出,请保存调卷规则生成文件");
+            }
+            checkExamFileExists(examId, examCourseDto, exportType);
+            Map<String, String> finishedPaperIdMap = extractConfig.getFinishedPaperIdMap();
+            Set<Entry<String, String>> entry = finishedPaperIdMap.entrySet();
+            Iterator<Entry<String, String>> iterator = entry.iterator();
+            while (iterator.hasNext()) {
+                Entry<String, String> next = iterator.next();
+                //paperId为key,paperType为value
+                paperIdMap.put(next.getValue(), next.getKey());
+            }
+        }
+        return paperIdMap;
+    }
+
+    /**
+     * 检查试卷文件是否存在
+     *
+     * @param examId
+     * @param examCourseDto
+     */
+    private void checkExamFileExists(String examId, ExamCourseDto examCourseDto, ExportType exportType) {
+        ExamFile examFileCondition = new ExamFile();
+        examFileCondition.setExamId(examId);
+        examFileCondition.setCourseId(examCourseDto.getCourseCode());
+
+        List<ExamFile> examfiles = examFileService.findExamFileListByExamFile(examFileCondition);
+
+        //检查是否都生成了试卷文件
+        boolean paperFlag = false;
+        if (exportType == ExportType.NORMAL) {
+            for (ExamFile examFile : examfiles) {
+                if (examFile.getExamFileType() == ExamFileType.PAPER) {
+                    paperFlag = true;
+                }
+            }
+        } else {
+            for (ExamFile examFile : examfiles) {
+                if (examFile.getExamFileType() == ExamFileType.COMPUTERTEST_PACKAGE) {
+                    paperFlag = true;
+                }
+            }
+        }
+
+        if (!paperFlag) {
+            String message = exportType == ExportType.NORMAL ? "考试文件" : "机考数据包";
+            throw new RuntimeException("该考试下的课程“" + examCourseDto.getCourseName() + "”" + message + "没有生成,不能批量导出,请重新保存调卷规则生成");
+        }
+    }
+
+    /**
+     * 将该考试下的所有课程试卷的结构生成到一张Excel表中
+     *
+     * @param examName
+     * @param paperIds
+     * @param exportStructure
+     * @throws Exception
+     */
+    private void makePaperStructure(String downloadDir, String examName, Map<String, String> paperIds, ExportStructure exportStructure) throws Exception {
+        logger.info("正在批量生成试卷结构...");
+        List<QuestionTypeNum> questionTypeNums = exportStructure.getQuestionTypeNums();
+        //客观题集合
+        List<ObjectiveQuestionStructure> objectiveQuestionStructureList = new ArrayList<ObjectiveQuestionStructure>();
+        //主观题集合
+        List<SubjectiveQuestionStructure> subjectiveQuestionStructureList = new ArrayList<SubjectiveQuestionStructure>();
+
+        ExportServiceManage esm = exportServiceManageRepo.findByOrgName(exportStructure.getOrgName());
+        if (esm == null) {
+            esm = exportServiceManageRepo.findByOrgName("陕西师范大学");
+        }
+        ExportPaperAbstractService exportPaperAbstractService = (ExportPaperAbstractService) SpringContextUtils.getBeanById(esm.getExportServiceName());
+        Set<Entry<String, String>> entrySet = paperIds.entrySet();
+        Iterator<Entry<String, String>> iterator = entrySet.iterator();
+
+        while (iterator.hasNext()) {
+            Entry<String, String> entry = iterator.next();
+            String paperId = entry.getKey();
+            String paperType = entry.getValue();
+            logger.info("初始化试卷:" + paperId);
+            PaperExp paperExp = initPaperExpService.initPaperExp(paperId);
+            logger.info("处理客观题...");
+            //添加客观题
+            List<PaperDetailExp> objectiveDetails = exportPaperAbstractService.getAllObjectiveDetails(paperExp);
+            //得到补齐后的客观题大题
+            List<PaperDetailExp> paperDetailExps = exportPaperAbstractService.fillObjectiveQuestions(objectiveDetails, questionTypeNums);
+            List<ObjectiveQuestionStructure> objectiveList = new ArrayList<ObjectiveQuestionStructure>();
+            for (PaperDetailExp paperDetailExp : paperDetailExps) {
+                for (PaperDetailUnitExp unit : paperDetailExp.getPaperDetailUnits()) {
+                    objectiveList.add(new ObjectiveQuestionStructure(paperExp, paperDetailExp, unit, paperType));
+                }
+            }
+            objectiveQuestionStructureList.addAll(objectiveList);
+            logger.info("处理客观题完成");
+            //添加主观题
+            logger.info("处理主观题...");
+            List<PaperDetailExp> subjectiveDetails = exportPaperAbstractService.getAllSubjectiveDetails(paperExp);
+            List<SubjectiveQuestionStructure> subjectiveList = new ArrayList<SubjectiveQuestionStructure>();
+            for (PaperDetailExp paperDetailExp : subjectiveDetails) {
+                for (PaperDetailUnitExp unit : paperDetailExp.getPaperDetailUnits()) {
+                    subjectiveList.add(new SubjectiveQuestionStructure(paperExp, paperDetailExp, unit, paperType));
+                }
+            }
+            subjectiveQuestionStructureList.addAll(subjectiveList);
+            logger.info("处理主观题完成");
+        }
+
+        ExcelWriter objectiveExcelExporter = new ExcelWriter(ObjectiveQuestionStructure.class);
+        String keguanFileName = examName + "_客观题.xlsx";
+        FileOutputStream out1 = getFileOutputStream(downloadDir, keguanFileName);
+        objectiveExcelExporter.write(keguanFileName, objectiveQuestionStructureList, out1);
+
+        ExcelWriter subjectiveExcelExporter = new ExcelWriter(SubjectiveQuestionStructure.class);
+        String zhuguanFileName = examName + "_主观题.xlsx";
+        FileOutputStream out2 = getFileOutputStream(downloadDir, zhuguanFileName);
+        subjectiveExcelExporter.write(zhuguanFileName, subjectiveQuestionStructureList, out2);
+
+        out1.close();
+        out2.close();
+        logger.info("批量生成试卷结构完成");
+    }
+
+    private FileOutputStream getFileOutputStream(String downloadDir, String fileName) throws IOException {
+        File directory = new File(downloadDir);
+        if (!directory.exists()) {
+            directory.mkdirs();
+        }
+        File file = new File(downloadDir + File.separator + fileName);
+        if (!file.exists()) {
+            file.createNewFile();
+        }
+        return new FileOutputStream(file);
+    }
+
 }