wangwei 7 éve
szülő
commit
e14f61917b

+ 96 - 0
examcloud-task-api-provider/src/main/java/cn/com/qmth/examcloud/task/api/controller/ExamStudentImportController.java

@@ -0,0 +1,96 @@
+package cn.com.qmth.examcloud.task.api.controller;
+
+import java.io.File;
+
+import javax.transaction.Transactional;
+
+import org.apache.commons.fileupload.disk.DiskFileItem;
+import org.apache.commons.io.FileUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
+
+import cn.com.qmth.examcloud.commons.base.util.DateUtil;
+import cn.com.qmth.examcloud.commons.base.util.DateUtil.DatePatterns;
+import cn.com.qmth.examcloud.commons.base.util.PathUtil;
+import cn.com.qmth.examcloud.commons.web.security.bean.User;
+import cn.com.qmth.examcloud.commons.web.support.ControllerSupport;
+import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
+import cn.com.qmth.examcloud.examwork.api.request.GetExamReq;
+import cn.com.qmth.examcloud.task.dao.ExamStudentImportRepo;
+import cn.com.qmth.examcloud.task.dao.entity.ExamStudentImportEntity;
+import cn.com.qmth.examcloud.task.dao.enums.ExamStudentImportStatus;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 考生导入
+ *
+ * @author WANGWEI
+ * @date 2018年7月31日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Transactional
+@RestController
+@RequestMapping("${$rmp.ctr.task}" + "examStudentImport")
+public class ExamStudentImportController extends ControllerSupport {
+
+	@Value("${$dir}")
+	private String dir;
+
+	private static final String EXAM_STUDENT_IMPORT_FILES = "exam_student_import_files";
+
+	@Autowired
+	ExamStudentImportRepo examStudentImportRepo;
+
+	@Autowired
+	ExamCloudService examCloudService;
+
+	@ApiOperation(value = "导入考试学生", notes = "导入")
+	@PostMapping("/import")
+	public void importExamStudent(@RequestParam Long examId,
+			@RequestParam CommonsMultipartFile file) throws Exception {
+		User accessUser = getAccessUser();
+		Long rootOrgId = accessUser.getRootOrgId();
+
+		GetExamReq req = new GetExamReq();
+		req.setId(examId);
+		req.setRootOrgId(accessUser.getRootOrgId());
+		examCloudService.getExam(req);
+
+		DiskFileItem item = (DiskFileItem) file.getFileItem();
+		File storeLocation = item.getStoreLocation();
+		String originalFilename = file.getOriginalFilename();
+
+		String suffix = originalFilename.substring(originalFilename.indexOf(originalFilename));
+		long batchId = System.currentTimeMillis();
+		String name = new StringBuilder().append(rootOrgId).append("_").append(examId).append("_")
+				.append(DateUtil.getNow(DatePatterns.YYYYMMDDHHMM)).toString();
+
+		String destFileName = name + suffix;
+		String resultFileName = name + ".txt";
+
+		String destFilePath = PathUtil
+				.getCanonicalPath(dir + "/" + EXAM_STUDENT_IMPORT_FILES + "/" + destFileName);
+		File destFile = new File(destFilePath);
+
+		FileUtils.copyFile(storeLocation, destFile);
+
+		ExamStudentImportEntity examStudentImport = new ExamStudentImportEntity();
+		examStudentImport.setBatchId(batchId);
+		examStudentImport.setFailNum(0L);
+		examStudentImport.setSuccessNum(0L);
+		examStudentImport.setTotalNum(0L);
+		examStudentImport.setFilePath(destFileName);
+		examStudentImport.setResultFilePath(resultFileName);
+		examStudentImport.setStatus(ExamStudentImportStatus.NONE);
+		examStudentImport.setRootOrgId(rootOrgId);
+		examStudentImport.setExamId(examId);
+
+		examStudentImportRepo.saveAndFlush(examStudentImport);
+	}
+
+}

+ 18 - 0
examcloud-task-dao/src/main/java/cn/com/qmth/examcloud/task/dao/ExamStudentImportRepo.java

@@ -0,0 +1,18 @@
+package cn.com.qmth.examcloud.task.dao;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+import cn.com.qmth.examcloud.task.dao.entity.ExamStudentImportEntity;
+import cn.com.qmth.examcloud.task.dao.enums.ExamStudentImportStatus;
+
+@Repository
+public interface ExamStudentImportRepo
+		extends
+			JpaRepository<ExamStudentImportEntity, Long>,
+			JpaSpecificationExecutor<ExamStudentImportEntity> {
+
+	ExamStudentImportEntity findFirstByStatusOrderByCreationTime(ExamStudentImportStatus status);
+
+}

+ 21 - 0
examcloud-task-dao/src/main/java/cn/com/qmth/examcloud/task/dao/ExamStudentTempRepo.java

@@ -0,0 +1,21 @@
+package cn.com.qmth.examcloud.task.dao;
+
+import java.util.List;
+
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+import cn.com.qmth.examcloud.task.dao.entity.ExamStudentTempEntity;
+
+@Repository
+public interface ExamStudentTempRepo
+		extends
+			JpaRepository<ExamStudentTempEntity, Long>,
+			JpaSpecificationExecutor<ExamStudentTempEntity> {
+
+	List<ExamStudentTempEntity> findByBatchIdAndStatusCodeIsNotNull(Long batchId,
+			Pageable pageable);
+
+}

+ 184 - 0
examcloud-task-dao/src/main/java/cn/com/qmth/examcloud/task/dao/entity/ExamStudentImportEntity.java

@@ -0,0 +1,184 @@
+package cn.com.qmth.examcloud.task.dao.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Index;
+import javax.persistence.Table;
+
+import cn.com.qmth.examcloud.commons.web.jpa.JpaEntity;
+import cn.com.qmth.examcloud.task.dao.enums.ExamStudentImportStatus;
+
+/**
+ * 考生导入表
+ *
+ * @author WANGWEI
+ * @date 2018年7月13日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Entity
+@Table(name = "EC_T_EXAM_STUDENT_IMPORT", indexes = {
+		@Index(name = "IDX_T_EXAM_STU_IMP_001001", columnList = "batchId", unique = true)})
+public class ExamStudentImportEntity extends JpaEntity {
+
+	private static final long serialVersionUID = -6030503185547639031L;
+
+	@Id
+	@GeneratedValue
+	private Long id;
+
+	/**
+	 * 批次ID
+	 */
+	private Long batchId;
+
+	/**
+	 * 考试ID
+	 */
+	private Long examId;
+
+	/**
+	 * 顶级机构ID
+	 */
+	private Long rootOrgId;
+
+	/**
+	 * 状态
+	 */
+	@Enumerated(EnumType.STRING)
+	private ExamStudentImportStatus status;
+
+	/**
+	 * 状态描述
+	 */
+	private String statusDesc;
+
+	/**
+	 * 文件名
+	 */
+	private String fileName;
+
+	/**
+	 * 文件路径
+	 */
+	private String filePath;
+
+	/**
+	 * 结果通知文件
+	 */
+	private String resultFilePath;
+
+	/**
+	 * 总条数
+	 */
+	private Long totalNum;
+
+	/**
+	 * 成功条数
+	 */
+	private Long successNum;
+
+	/**
+	 * 失败条数
+	 */
+	private Long failNum;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getBatchId() {
+		return batchId;
+	}
+
+	public void setBatchId(Long batchId) {
+		this.batchId = batchId;
+	}
+
+	public Long getExamId() {
+		return examId;
+	}
+
+	public void setExamId(Long examId) {
+		this.examId = examId;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public ExamStudentImportStatus getStatus() {
+		return status;
+	}
+
+	public void setStatus(ExamStudentImportStatus status) {
+		this.status = status;
+	}
+
+	public String getStatusDesc() {
+		return statusDesc;
+	}
+
+	public void setStatusDesc(String statusDesc) {
+		this.statusDesc = statusDesc;
+	}
+
+	public String getFileName() {
+		return fileName;
+	}
+
+	public void setFileName(String fileName) {
+		this.fileName = fileName;
+	}
+
+	public String getFilePath() {
+		return filePath;
+	}
+
+	public void setFilePath(String filePath) {
+		this.filePath = filePath;
+	}
+
+	public String getResultFilePath() {
+		return resultFilePath;
+	}
+
+	public void setResultFilePath(String resultFilePath) {
+		this.resultFilePath = resultFilePath;
+	}
+
+	public Long getTotalNum() {
+		return totalNum;
+	}
+
+	public void setTotalNum(Long totalNum) {
+		this.totalNum = totalNum;
+	}
+
+	public Long getSuccessNum() {
+		return successNum;
+	}
+
+	public void setSuccessNum(Long successNum) {
+		this.successNum = successNum;
+	}
+
+	public Long getFailNum() {
+		return failNum;
+	}
+
+	public void setFailNum(Long failNum) {
+		this.failNum = failNum;
+	}
+
+}

+ 349 - 0
examcloud-task-dao/src/main/java/cn/com/qmth/examcloud/task/dao/entity/ExamStudentTempEntity.java

@@ -0,0 +1,349 @@
+package cn.com.qmth.examcloud.task.dao.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Index;
+import javax.persistence.Table;
+
+import cn.com.qmth.examcloud.commons.web.jpa.JpaEntity;
+
+/**
+ * 考生临时表
+ *
+ * @author WANGWEI
+ * @date 2018年7月13日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Entity
+@Table(name = "EC_T_EXAM_STUDENT_TMP", indexes = {
+		@Index(name = "IDX_T_EXAM_STU_001001", columnList = "batchId", unique = true)})
+public class ExamStudentTempEntity extends JpaEntity {
+
+	private static final long serialVersionUID = -6030503185547639031L;
+
+	@Id
+	@GeneratedValue
+	private Long id;
+
+	/**
+	 * 批次ID
+	 */
+	private Long batchId;
+
+	/**
+	 * 状态码
+	 */
+	private String statusCode;
+
+	/**
+	 * 状态描述
+	 */
+	private String statusDesc;
+
+	/**
+	 * 姓名
+	 */
+	private String name;
+
+	/**
+	 * 考试ID
+	 */
+	private Long examId;
+
+	/**
+	 * 学校id
+	 */
+	private Long rootOrgId;
+
+	/**
+	 * 学习中心id
+	 */
+	private Long orgId;
+
+	/**
+	 * 学习中心code
+	 */
+	private String orgCode;
+
+	/**
+	 * 学习中心名称
+	 */
+	private String orgName;
+
+	/**
+	 * 学号
+	 */
+	private String studentCode;
+
+	/**
+	 * 身份证号
+	 */
+	private String identityNumber;
+
+	/**
+	 * 课程ID
+	 */
+	private Long courseId;
+
+	/**
+	 * 课程code
+	 */
+	private String courseCode;
+
+	/**
+	 * 课程名称
+	 */
+	private String courseName;
+
+	/**
+	 * 课程等级
+	 */
+	private String courseLevel;
+
+	/**
+	 * 试卷类型
+	 */
+	private String paperType;
+
+	/**
+	 * 专业名称
+	 */
+	private String specialtyName;
+
+	/**
+	 * 专业code
+	 */
+	private String specialtyCode;
+
+	/**
+	 * 年级
+	 */
+	private String grade;
+
+	/**
+	 * 学生用户id
+	 */
+	private Long studentId;
+
+	/**
+	 * 考点
+	 */
+	private String examSite;
+
+	/**
+	 * 信息采集人
+	 */
+	private String infoCollector;
+
+	/**
+	 * 学生电话
+	 */
+	private String phone;
+
+	/**
+	 * excel行号
+	 */
+	private Long lineNum;
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Long getBatchId() {
+		return batchId;
+	}
+
+	public void setBatchId(Long batchId) {
+		this.batchId = batchId;
+	}
+
+	public String getStatusCode() {
+		return statusCode;
+	}
+
+	public void setStatusCode(String statusCode) {
+		this.statusCode = statusCode;
+	}
+
+	public String getStatusDesc() {
+		return statusDesc;
+	}
+
+	public void setStatusDesc(String statusDesc) {
+		this.statusDesc = statusDesc;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Long getExamId() {
+		return examId;
+	}
+
+	public void setExamId(Long examId) {
+		this.examId = examId;
+	}
+
+	public Long getRootOrgId() {
+		return rootOrgId;
+	}
+
+	public void setRootOrgId(Long rootOrgId) {
+		this.rootOrgId = rootOrgId;
+	}
+
+	public Long getOrgId() {
+		return orgId;
+	}
+
+	public void setOrgId(Long orgId) {
+		this.orgId = orgId;
+	}
+
+	public String getOrgCode() {
+		return orgCode;
+	}
+
+	public void setOrgCode(String orgCode) {
+		this.orgCode = orgCode;
+	}
+
+	public String getOrgName() {
+		return orgName;
+	}
+
+	public void setOrgName(String orgName) {
+		this.orgName = orgName;
+	}
+
+	public String getStudentCode() {
+		return studentCode;
+	}
+
+	public void setStudentCode(String studentCode) {
+		this.studentCode = studentCode;
+	}
+
+	public String getIdentityNumber() {
+		return identityNumber;
+	}
+
+	public void setIdentityNumber(String identityNumber) {
+		this.identityNumber = identityNumber;
+	}
+
+	public Long getCourseId() {
+		return courseId;
+	}
+
+	public void setCourseId(Long courseId) {
+		this.courseId = courseId;
+	}
+
+	public String getCourseCode() {
+		return courseCode;
+	}
+
+	public void setCourseCode(String courseCode) {
+		this.courseCode = courseCode;
+	}
+
+	public String getCourseName() {
+		return courseName;
+	}
+
+	public void setCourseName(String courseName) {
+		this.courseName = courseName;
+	}
+
+	public String getCourseLevel() {
+		return courseLevel;
+	}
+
+	public void setCourseLevel(String courseLevel) {
+		this.courseLevel = courseLevel;
+	}
+
+	public String getPaperType() {
+		return paperType;
+	}
+
+	public void setPaperType(String paperType) {
+		this.paperType = paperType;
+	}
+
+	public String getSpecialtyName() {
+		return specialtyName;
+	}
+
+	public void setSpecialtyName(String specialtyName) {
+		this.specialtyName = specialtyName;
+	}
+
+	public String getSpecialtyCode() {
+		return specialtyCode;
+	}
+
+	public void setSpecialtyCode(String specialtyCode) {
+		this.specialtyCode = specialtyCode;
+	}
+
+	public String getGrade() {
+		return grade;
+	}
+
+	public void setGrade(String grade) {
+		this.grade = grade;
+	}
+
+	public Long getStudentId() {
+		return studentId;
+	}
+
+	public void setStudentId(Long studentId) {
+		this.studentId = studentId;
+	}
+
+	public String getExamSite() {
+		return examSite;
+	}
+
+	public void setExamSite(String examSite) {
+		this.examSite = examSite;
+	}
+
+	public String getInfoCollector() {
+		return infoCollector;
+	}
+
+	public void setInfoCollector(String infoCollector) {
+		this.infoCollector = infoCollector;
+	}
+
+	public String getPhone() {
+		return phone;
+	}
+
+	public void setPhone(String phone) {
+		this.phone = phone;
+	}
+
+	public Long getLineNum() {
+		return lineNum;
+	}
+
+	public void setLineNum(Long lineNum) {
+		this.lineNum = lineNum;
+	}
+
+}

+ 35 - 0
examcloud-task-dao/src/main/java/cn/com/qmth/examcloud/task/dao/enums/ExamStudentImportStatus.java

@@ -0,0 +1,35 @@
+package cn.com.qmth.examcloud.task.dao.enums;
+
+/**
+ * 类注释
+ *
+ * @author WANGWEI
+ * @date 2018年7月31日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+public enum ExamStudentImportStatus {
+
+	NONE("未开始"), FILE_PARSING("文件解析中"), FILE_PARSING_COMPLETE("文件解析完成"), DATA_PROCESSING(
+			"数据处理中"), DATA_PROCESSING_COMPLETE("数据处理完毕"), ERROR("错误");
+
+	// ===========================================================================
+
+	/**
+	 * 描述
+	 */
+	private String desc;
+
+	/**
+	 * 构造函数
+	 *
+	 * @param desc
+	 */
+	private ExamStudentImportStatus(String desc) {
+		this.desc = desc;
+	}
+
+	public String getDesc() {
+		return desc;
+	}
+
+}

+ 12 - 0
examcloud-task-service/pom.xml

@@ -18,5 +18,17 @@
 			<artifactId>examcloud-core-oe-api-client</artifactId>
 			<version>${examcloud.version}</version>
 		</dependency>
+
+		<dependency>
+			<groupId>cn.com.qmth.examcloud.core.basic</groupId>
+			<artifactId>examcloud-core-basic-api-client</artifactId>
+			<version>${examcloud.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>cn.com.qmth.examcloud.core.examwork</groupId>
+			<artifactId>examcloud-core-examwork-api-client</artifactId>
+			<version>${examcloud.version}</version>
+		</dependency>
+
 	</dependencies>
 </project>

+ 237 - 0
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/ExamStudentImportDataProcessingTask.java

@@ -0,0 +1,237 @@
+package cn.com.qmth.examcloud.task.service.job;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.io.FileUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.stereotype.Component;
+
+import com.google.common.collect.Maps;
+
+import cn.com.qmth.examcloud.common.dto.core.enums.CourseLevel;
+import cn.com.qmth.examcloud.commons.base.exception.StatusException;
+import cn.com.qmth.examcloud.commons.base.util.PathUtil;
+import cn.com.qmth.examcloud.core.basic.api.CourseCloudService;
+import cn.com.qmth.examcloud.core.basic.api.OrgCloudService;
+import cn.com.qmth.examcloud.core.basic.api.StudentCloudService;
+import cn.com.qmth.examcloud.core.basic.api.bean.CourseBean;
+import cn.com.qmth.examcloud.core.basic.api.bean.OrgBean;
+import cn.com.qmth.examcloud.core.basic.api.request.GetCourseReq;
+import cn.com.qmth.examcloud.core.basic.api.request.GetOrgReq;
+import cn.com.qmth.examcloud.core.basic.api.request.InsertOrUpdateStudentReq;
+import cn.com.qmth.examcloud.core.basic.api.response.GetCourseResp;
+import cn.com.qmth.examcloud.core.basic.api.response.GetOrgResp;
+import cn.com.qmth.examcloud.core.basic.api.response.InsertOrUpdateStudentResp;
+import cn.com.qmth.examcloud.examwork.api.ExamCloudService;
+import cn.com.qmth.examcloud.examwork.api.ExamStudentCloudService;
+import cn.com.qmth.examcloud.examwork.api.request.SaveExamStudentReq;
+import cn.com.qmth.examcloud.task.base.AbstractTask;
+import cn.com.qmth.examcloud.task.base.ScheduleJob;
+import cn.com.qmth.examcloud.task.base.TaskTracker;
+import cn.com.qmth.examcloud.task.dao.ExamStudentImportRepo;
+import cn.com.qmth.examcloud.task.dao.ExamStudentTempRepo;
+import cn.com.qmth.examcloud.task.dao.entity.ExamStudentImportEntity;
+import cn.com.qmth.examcloud.task.dao.entity.ExamStudentTempEntity;
+import cn.com.qmth.examcloud.task.dao.enums.ExamStudentImportStatus;
+
+/**
+ * 考生导入-文件解析
+ *
+ * @author WANGWEI
+ * @date 2018年7月31日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Component("examStudentImportDataProcessingTask")
+public class ExamStudentImportDataProcessingTask extends AbstractTask {
+
+	@Value("${$dir}")
+	private String dir;
+
+	private static final String EXAM_STUDENT_IMPORT_FILES = "exam_student_import_files";
+
+	@Autowired
+	TaskTracker TaskTracker;
+
+	@Autowired
+	ExamStudentImportRepo examStudentImportRepo;
+
+	@Autowired
+	ExamStudentTempRepo examStudentTempRepo;
+
+	@Autowired
+	CourseCloudService courseCloudService;
+
+	@Autowired
+	OrgCloudService orgCloudService;
+
+	@Autowired
+	StudentCloudService studentCloudService;
+
+	@Autowired
+	ExamCloudService examCloudService;
+
+	@Autowired
+	ExamStudentCloudService examStudentCloudService;
+
+	@Override
+	public void run(ScheduleJob scheduleJob) throws Exception {
+
+		ExamStudentImportEntity importEntity = examStudentImportRepo
+				.findFirstByStatusOrderByCreationTime(
+						ExamStudentImportStatus.FILE_PARSING_COMPLETE);
+		if (null == importEntity) {
+			return;
+		}
+
+		importEntity.setStatus(ExamStudentImportStatus.FILE_PARSING);
+		examStudentImportRepo.saveAndFlush(importEntity);
+
+		process(importEntity);
+	}
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param importEntity
+	 */
+	private void process(ExamStudentImportEntity importEntity) {
+		List<Map<String, Object>> failRecords = Collections
+				.synchronizedList(new ArrayList<Map<String, Object>>());
+
+		foreach(importEntity, failRecords);
+
+		StringBuilder sb = new StringBuilder();
+		for (Map<String, Object> cur : failRecords) {
+			sb.append("line:").append(cur.get("lineNum")).append(cur.get("msg")).append("\n");
+		}
+		sb.append("==============================================\n");
+		String resultFilePath = PathUtil.getCanonicalPath(
+				dir + "/" + EXAM_STUDENT_IMPORT_FILES + "/" + importEntity.getResultFilePath());
+		File resultFile = new File(resultFilePath);
+
+		try {
+			FileUtils.writeStringToFile(resultFile, sb.toString(), "UTF-8", true);
+		} catch (IOException e) {
+			importEntity.setStatus(ExamStudentImportStatus.ERROR);
+			importEntity.setStatusDesc("导入报告写入失败");
+			examStudentImportRepo.saveAndFlush(importEntity);
+			return;
+		}
+
+		importEntity.setStatus(ExamStudentImportStatus.DATA_PROCESSING_COMPLETE);
+		examStudentImportRepo.saveAndFlush(importEntity);
+
+	}
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param importEntity
+	 * @param failRecords
+	 */
+	private void foreach(ExamStudentImportEntity importEntity,
+			List<Map<String, Object>> failRecords) {
+		Long batchId = importEntity.getBatchId();
+
+		while (true) {
+			Pageable pageable = new PageRequest(0, 100, Sort.Direction.DESC, "updateTime");
+			List<ExamStudentTempEntity> list = examStudentTempRepo
+					.findByBatchIdAndStatusCodeIsNotNull(batchId, pageable);
+			if (CollectionUtils.isEmpty(list)) {
+				break;
+			}
+
+			for (ExamStudentTempEntity cur : list) {
+				saveExamStudent(cur, failRecords);
+			}
+		}
+	}
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param entity
+	 * @param failRecords
+	 */
+	private void saveExamStudent(ExamStudentTempEntity entity,
+			List<Map<String, Object>> failRecords) {
+		Long rootOrgId = entity.getRootOrgId();
+		String courseCode = entity.getCourseCode();
+
+		try {
+			GetCourseReq req = new GetCourseReq();
+			req.setRootOrgId(rootOrgId);
+			req.setCode(courseCode);
+			GetCourseResp resp = courseCloudService.getCourse(req);
+			CourseBean courseBean = resp.getCourseBean();
+			entity.setCourseId(courseBean.getId());
+		} catch (StatusException e) {
+			Map<String, Object> map = Maps.newHashMap();
+			map.put("lineNum", entity.getLineNum());
+			map.put("msg", e.getDesc());
+			failRecords.add(map);
+		}
+
+		try {
+			GetOrgReq req = new GetOrgReq();
+			GetOrgResp resp = orgCloudService.getOrg(req);
+			OrgBean org = resp.getOrg();
+			entity.setOrgId(org.getId());
+		} catch (StatusException e) {
+			Map<String, Object> map = Maps.newHashMap();
+			map.put("lineNum", entity.getLineNum());
+			map.put("msg", e.getDesc());
+			failRecords.add(map);
+		}
+
+		InsertOrUpdateStudentReq saveStudentReq = new InsertOrUpdateStudentReq();
+		saveStudentReq.setIdentityNumber(entity.getIdentityNumber());
+		saveStudentReq.setName(entity.getName());
+		saveStudentReq.setPhoneNumber(entity.getPhone());
+		saveStudentReq.setOrgCode(entity.getOrgCode());
+		saveStudentReq.setOrgId(entity.getOrgId());
+		saveStudentReq.setRootOrgId(rootOrgId);
+		saveStudentReq.setStudentCode(entity.getStudentCode());
+
+		InsertOrUpdateStudentResp insertOrUpdateStudentResp = studentCloudService
+				.insertOrUpdateStudent(saveStudentReq);
+
+		Long studentId = insertOrUpdateStudentResp.getStudentId();
+
+		SaveExamStudentReq sReq = new SaveExamStudentReq();
+		sReq.setCourseLevel(entity.getCourseLevel());
+
+		CourseLevel courseLevel = CourseLevel.getCourseLevel(entity.getCourseLevel());
+		sReq.setCourseLevel(courseLevel.name());
+		sReq.setCourseCode(entity.getCourseCode());
+		sReq.setCourseName(entity.getCourseName());
+		sReq.setExamId(entity.getExamId());
+		sReq.setStudentId(studentId);
+		sReq.setIdentityNumber(entity.getIdentityNumber());
+		sReq.setPaperType(entity.getPaperType());
+		sReq.setRootOrgId(rootOrgId);
+		sReq.setStudentCode(entity.getStudentCode());
+		sReq.setStudentName(entity.getName());
+		sReq.setPaperType("O");
+		examStudentCloudService.saveExamStudent(sReq);
+
+	}
+
+	@Override
+	public TaskTracker getTaskTracker() {
+		return TaskTracker;
+	}
+}

+ 289 - 0
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/ExamStudentImportParsingFileTask.java

@@ -0,0 +1,289 @@
+package cn.com.qmth.examcloud.task.service.job;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+import cn.com.qmth.examcloud.commons.base.helpers.poi.ExcelParser;
+import cn.com.qmth.examcloud.commons.base.util.PathUtil;
+import cn.com.qmth.examcloud.task.base.AbstractTask;
+import cn.com.qmth.examcloud.task.base.ScheduleJob;
+import cn.com.qmth.examcloud.task.base.TaskTracker;
+import cn.com.qmth.examcloud.task.dao.ExamStudentImportRepo;
+import cn.com.qmth.examcloud.task.dao.ExamStudentTempRepo;
+import cn.com.qmth.examcloud.task.dao.entity.ExamStudentImportEntity;
+import cn.com.qmth.examcloud.task.dao.entity.ExamStudentTempEntity;
+import cn.com.qmth.examcloud.task.dao.enums.ExamStudentImportStatus;
+
+/**
+ * 考生导入-文件解析
+ *
+ * @author WANGWEI
+ * @date 2018年7月31日
+ * @Copyright (c) 2018-? http://qmth.com.cn All Rights Reserved.
+ */
+@Component("examStudentImportParsingFileTask")
+public class ExamStudentImportParsingFileTask extends AbstractTask {
+
+	@Value("${$dir}")
+	private String dir;
+
+	private static final String EXAM_STUDENT_IMPORT_FILES = "exam_student_import_files";
+
+	private static final String[] EXCEL_HEADER = new String[]{"姓名", "学号", "身份证号", "学习中心代码",
+			"学习中心名称", "课程代码", "课程名称", "试卷类型", "专业", "考点", "信息采集人", "学生电话", "年级"};
+
+	@Autowired
+	TaskTracker TaskTracker;
+
+	@Autowired
+	ExamStudentImportRepo examStudentImportRepo;
+
+	@Autowired
+	ExamStudentTempRepo examStudentTempRepo;
+
+	@Override
+	public void run(ScheduleJob scheduleJob) throws Exception {
+
+		ExamStudentImportEntity importEntity = examStudentImportRepo
+				.findFirstByStatusOrderByCreationTime(ExamStudentImportStatus.NONE);
+		if (null == importEntity) {
+			return;
+		}
+
+		importEntity.setStatus(ExamStudentImportStatus.FILE_PARSING);
+		examStudentImportRepo.saveAndFlush(importEntity);
+
+		importExcel(importEntity);
+	}
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param importEntity
+	 */
+	private void importExcel(ExamStudentImportEntity importEntity) {
+		String destFilePath = PathUtil.getCanonicalPath(
+				dir + "/" + EXAM_STUDENT_IMPORT_FILES + "/" + importEntity.getFilePath());
+		String resultFilePath = PathUtil.getCanonicalPath(
+				dir + "/" + EXAM_STUDENT_IMPORT_FILES + "/" + importEntity.getResultFilePath());
+		Workbook workBook = ExcelParser.getWorkBook(new File(destFilePath),
+				importEntity.getFileName());
+
+		File file = new File(destFilePath);
+
+		if (!file.exists()) {
+			importEntity.setStatus(ExamStudentImportStatus.ERROR);
+			importEntity.setStatusDesc("文件不存在");
+			examStudentImportRepo.saveAndFlush(importEntity);
+			return;
+		}
+
+		Sheet sheet = workBook.getSheetAt(0);
+
+		List<String[]> lineList = ExcelParser.readSheet(sheet, 13);
+		ExcelParser.close(workBook);
+
+		if (CollectionUtils.isEmpty(lineList)) {
+			importEntity.setStatus(ExamStudentImportStatus.ERROR);
+			importEntity.setStatusDesc("Excel 没有内容");
+			examStudentImportRepo.saveAndFlush(importEntity);
+			return;
+		}
+
+		Long batchId = importEntity.getBatchId();
+		Long rootOrgId = importEntity.getRootOrgId();
+		Long examId = importEntity.getExamId();
+		List<ExamStudentTempEntity> list = Lists.newArrayList();
+
+		List<Map<String, Object>> failRecords = Collections
+				.synchronizedList(new ArrayList<Map<String, Object>>());
+
+		for (int i = 0; i < lineList.size(); i++) {
+			String[] line = lineList.get(i);
+			if (0 == i) {
+				if (headerError(line)) {
+					importEntity.setStatus(ExamStudentImportStatus.ERROR);
+					importEntity.setStatusDesc("EXCEL表头错误");
+					examStudentImportRepo.saveAndFlush(importEntity);
+					return;
+				}
+				continue;
+			}
+
+			ExamStudentTempEntity es = new ExamStudentTempEntity();
+			es.setLineNum((long) 1 + i);
+			es.setRootOrgId(rootOrgId);
+			es.setExamId(examId);
+			es.setBatchId(batchId);
+			es.setName(trimAndNullIfBlank(line[0]));
+			es.setStudentCode(trimAndNullIfBlank(line[1]));
+			es.setIdentityNumber(trimAndNullIfBlank(line[2]));
+			es.setOrgCode(trimAndNullIfBlank(line[3]));
+			es.setOrgName(trimAndNullIfBlank(line[4]));
+			es.setCourseCode(trimAndNullIfBlank(line[5]));
+			es.setCourseName(trimAndNullIfBlank(line[6]));
+			es.setPaperType(trimAndNullIfBlank(line[7]));
+			es.setSpecialtyName(trimAndNullIfBlank(line[8]));
+			es.setExamSite(trimAndNullIfBlank(line[9]));
+			es.setInfoCollector(trimAndNullIfBlank(line[10]));
+			es.setPhone(trimAndNullIfBlank(line[11]));
+			es.setGrade(trimAndNullIfBlank(line[12]));
+
+			if (hasError(failRecords, es)) {
+				continue;
+			}
+
+			list.add(es);
+			if (0 == i % 100) {
+				examStudentTempRepo.save(list);
+
+				list = Lists.newArrayList();
+			}
+		}
+
+		examStudentTempRepo.save(list);
+
+		StringBuilder sb = new StringBuilder();
+		for (Map<String, Object> cur : failRecords) {
+			sb.append("line:").append(cur.get("lineNum")).append(cur.get("msg")).append("\n");
+		}
+		sb.append("==============================================\n");
+		File resultFile = new File(resultFilePath);
+
+		try {
+			FileUtils.writeStringToFile(resultFile, sb.toString(), "UTF-8", true);
+		} catch (IOException e) {
+			importEntity.setStatus(ExamStudentImportStatus.ERROR);
+			importEntity.setStatusDesc("导入报告写入失败");
+			examStudentImportRepo.saveAndFlush(importEntity);
+			return;
+		}
+
+		importEntity.setStatus(ExamStudentImportStatus.FILE_PARSING_COMPLETE);
+		examStudentImportRepo.saveAndFlush(importEntity);
+
+	}
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param failRecords
+	 * @param entity
+	 * @return
+	 */
+	public boolean hasError(List<Map<String, Object>> failRecords, ExamStudentTempEntity entity) {
+		boolean hasError = false;
+		StringBuilder sb = new StringBuilder();
+
+		String name = entity.getName();
+		if (StringUtils.isBlank(name)) {
+			sb.append("  姓名不能为空");
+			hasError = true;
+		} else if (20 < name.length()) {
+			sb.append("  姓名不能超过20个字符");
+			hasError = true;
+		}
+
+		String identityNumber = entity.getIdentityNumber();
+		if (StringUtils.isBlank(identityNumber)) {
+			sb.append("  身份证号不能为空");
+			hasError = true;
+		} else if (identityNumber.length() < 6) {
+			sb.append("  身份证号至少为6个字符");
+			hasError = true;
+		} else if (identityNumber.length() > 30) {
+			sb.append("  身份证号不能超过30个字符");
+			hasError = true;
+		}
+
+		String studentCode = entity.getStudentCode();
+		if (StringUtils.isNotBlank(studentCode)) {
+			if (studentCode.length() < 6) {
+				sb.append("  学号至少为6个字符");
+				hasError = true;
+			} else if (studentCode.length() > 30) {
+				sb.append("  学号不能超过30个字符");
+				hasError = true;
+			}
+		}
+
+		String courseCode = entity.getCourseCode();
+		if (StringUtils.isBlank(courseCode)) {
+			sb.append("  课程代码不能为空");
+			hasError = true;
+		} else if (courseCode.length() > 30) {
+			sb.append("  课程代码不能超过30个字符");
+			hasError = true;
+		}
+
+		String orgCode = entity.getOrgCode();
+		if (StringUtils.isBlank(orgCode)) {
+			sb.append("  学习中心代码不能为空");
+			hasError = true;
+		} else if (orgCode.length() > 30) {
+			sb.append("  学习中心代码不能超过30个字符");
+			hasError = true;
+		}
+
+		if (hasError) {
+			Map<String, Object> map = Maps.newHashMap();
+			map.put("lineNum", entity.getLineNum());
+			map.put("msg", sb.toString());
+			failRecords.add(map);
+		}
+
+		return hasError;
+	}
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param s
+	 * @return
+	 */
+	private String trimAndNullIfBlank(String s) {
+		if (StringUtils.isBlank(s)) {
+			return null;
+		}
+		return s.trim();
+	}
+
+	/**
+	 * 方法注释
+	 *
+	 * @author WANGWEI
+	 * @param header
+	 */
+	private boolean headerError(String[] header) {
+		for (int i = 0; i < EXCEL_HEADER.length; i++) {
+			if (!EXCEL_HEADER[i].equals(header[i].trim())) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	@Override
+	public TaskTracker getTaskTracker() {
+		return TaskTracker;
+	}
+}

+ 5 - 1
examcloud-task-starter/src/main/resources/application-dev.properties

@@ -5,4 +5,8 @@ spring.datasource.password=root
 spring.redis.host=192.168.10.30
 spring.redis.port=6379
 
-eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
+eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
+
+
+$tempDir=D:/Temp/tempDir
+$dir=D:/Temp/dir

+ 4 - 1
examcloud-task-starter/src/main/resources/application-prod.properties

@@ -9,4 +9,7 @@ eureka.client.serviceUrl.defaultZone=http://192.168.1.70:1111/eureka/
 spring.redis.host=r-wz97e520d2701e54555.redis.rds.aliyuncs.com
 spring.redis.port=6379
 spring.redis.password=Qmth87863577
-spring.redis.pool.max-active=2000
+spring.redis.pool.max-active=2000
+
+$tempDir=/root/project/examcloud/examcloud-task/tempDir
+$dir=/root/project/examcloud/examcloud-task/dir

+ 4 - 1
examcloud-task-starter/src/main/resources/application-test.properties

@@ -7,4 +7,7 @@ spring.datasource.test-on-borrow=true
 spring.redis.host=192.168.10.30
 spring.redis.port=6379
 
-eureka.client.serviceUrl.defaultZone=http://192.168.10.30:1111/eureka/
+eureka.client.serviceUrl.defaultZone=http://192.168.10.30:1111/eureka/
+
+$tempDir=/root/project/examcloud/examcloud-task/tempDir
+$dir=/root/project/examcloud/examcloud-task/dir