浏览代码

merge from release_v4.0.1

deason 4 年之前
父节点
当前提交
d43a010463
共有 16 个文件被更改,包括 583 次插入463 次删除
  1. 10 4
      .gitignore
  2. 2 0
      examcloud-task-api-provider/src/main/java/cn/com/qmth/examcloud/task/api/provider/DataSyncCloudServiceProvider.java
  3. 1 1
      examcloud-task-base/src/main/java/cn/com/qmth/examcloud/task/base/multithread/Consumer.java
  4. 25 0
      examcloud-task-dao/src/main/java/cn/com/qmth/examcloud/task/dao/entity/ExamStudentTempEntity.java
  5. 2 0
      examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/ExamStudentImportDataProcessingTask.java
  6. 390 346
      examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/ExamStudentImportParsingFileTask.java
  7. 4 0
      examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/ExamStudentOnlineCountTask.java
  8. 4 0
      examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/StudentCumulativeCountTask.java
  9. 4 0
      examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/StudentOnlineCountTask.java
  10. 33 0
      examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/StudentOperateLogTask.java
  11. 4 0
      examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/StudentTotalCountTask.java
  12. 4 0
      examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/UserOnlineCountTask.java
  13. 1 1
      examcloud-task-starter/src/main/resources/application.properties
  14. 99 73
      examcloud-task-starter/src/main/resources/log4j2.xml
  15. 0 19
      jenkins-dev.sh
  16. 0 19
      jenkins-test.sh

+ 10 - 4
.gitignore

@@ -1,13 +1,19 @@
+*.class
+
+# Proguard folder generated by ide
 .project
 .classpath
 .settings
 target/
 .idea/
 *.iml
-*test/
-# Package Files #
-*.jar
-logs/
 
+# Log Files
+*.log
+*.class
 
 
+# Package Files #
+*.jar
+*.war
+*.ear

+ 2 - 0
examcloud-task-api-provider/src/main/java/cn/com/qmth/examcloud/task/api/provider/DataSyncCloudServiceProvider.java

@@ -162,6 +162,8 @@ public class DataSyncCloudServiceProvider extends ControllerSupport
 		r.setRemark(req.getRemark());
 		r.setInfoCollector(req.getInfoCollector());
 		r.setExamSite(req.getExamSite());
+		r.setExamStageId(req.getExamStageId());
+		r.setExamStageOrder(req.getExamStageOrder());
 
 		r.setExt1(req.getExt1());
 		r.setExt2(req.getExt2());

+ 1 - 1
examcloud-task-base/src/main/java/cn/com/qmth/examcloud/task/base/multithread/Consumer.java

@@ -36,7 +36,7 @@ public abstract class Consumer<T>  extends Thread{
 			}
 		} catch (Exception e) {
 			basket.setExcuteError(true);
-			logger.info("消费线程处理出错",e);
+			logger.error("消费线程处理出错",e);
 		}finally {
 			basket.countDown();
 			logger.info("*******************Consumer:"+Thread.currentThread().getId()+" stop");

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

@@ -159,6 +159,16 @@ public class ExamStudentTempEntity extends JpaEntity {
 	 */
 	private Date specialEndTime;
 
+	/**
+	 * 场次id
+	 */
+	private Long examStageId;
+
+	/**
+	 * 场次号
+	 */
+	private Integer examStageOrder;
+
 	/**
 	 * 扩展属性1
 	 */
@@ -440,4 +450,19 @@ public class ExamStudentTempEntity extends JpaEntity {
 		this.ext5 = ext5;
 	}
 
+	public Long getExamStageId() {
+		return examStageId;
+	}
+
+	public void setExamStageId(Long examStageId) {
+		this.examStageId = examStageId;
+	}
+
+	public Integer getExamStageOrder() {
+		return examStageOrder;
+	}
+
+	public void setExamStageOrder(Integer examStageOrder) {
+		this.examStageOrder = examStageOrder;
+	}
 }

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

@@ -290,6 +290,8 @@ public class ExamStudentImportDataProcessingTask extends AbstractTask {
 			sReq.setExt3(entity.getExt3());
 			sReq.setExt4(entity.getExt4());
 			sReq.setExt5(entity.getExt5());
+			sReq.setExamStageId(entity.getExamStageId());
+			sReq.setExamStageOrder(entity.getExamStageOrder());
 
 			examStudentCloudService.saveExamStudent(sReq);
 

+ 390 - 346
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/ExamStudentImportParsingFileTask.java

@@ -1,30 +1,16 @@
 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.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
+import cn.com.qmth.examcloud.api.commons.enums.ExamSpecialSettingsType;
 import cn.com.qmth.examcloud.commons.helpers.poi.ExcelReader;
 import cn.com.qmth.examcloud.commons.util.BooleanUtil;
 import cn.com.qmth.examcloud.commons.util.DateUtil;
 import cn.com.qmth.examcloud.commons.util.PathUtil;
+import cn.com.qmth.examcloud.examwork.api.ExamStageCloudService;
+import cn.com.qmth.examcloud.examwork.api.bean.ExamStageBean;
+import cn.com.qmth.examcloud.examwork.api.request.GetExamStageReq;
+import cn.com.qmth.examcloud.examwork.api.response.GetExamStageResp;
+import cn.com.qmth.examcloud.support.cache.CacheHelper;
+import cn.com.qmth.examcloud.support.cache.bean.ExamSettingsCacheBean;
 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;
@@ -34,6 +20,19 @@ import cn.com.qmth.examcloud.web.config.SystemProperties;
 import cn.com.qmth.examcloud.web.task.AbstractTask;
 import cn.com.qmth.examcloud.web.task.ScheduleJob;
 import cn.com.qmth.examcloud.web.task.TaskTracker;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
 
 /**
  * 考生导入-文件解析
@@ -45,329 +44,374 @@ import cn.com.qmth.examcloud.web.task.TaskTracker;
 @Component("examStudentImportParsingFileTask")
 public class ExamStudentImportParsingFileTask extends AbstractTask {
 
-	@Autowired
-	SystemProperties systemConfig;
-
-	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.FILE_PARSING);
-
-		if (null == importEntity) {
-			importEntity = examStudentImportRepo
-					.findFirstByStatusOrderByCreationTime(ExamStudentImportStatus.NONE);
-		}
-
-		if (null == importEntity) {
-			return;
-		}
-
-		importEntity.setStatus(ExamStudentImportStatus.FILE_PARSING);
-		examStudentImportRepo.saveAndFlush(importEntity);
-
-		try {
-			importExcel(importEntity);
-		} catch (Exception e) {
-			debugLog.error("文件解析异常", e);
-			importEntity.setStatus(ExamStudentImportStatus.ERROR);
-			importEntity.setErrorDesc("文件解析异常");
-			examStudentImportRepo.saveAndFlush(importEntity);
-			return;
-		}
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @author WANGWEI
-	 * @param importEntity
-	 */
-	private void importExcel(ExamStudentImportEntity importEntity) {
-		String destFilePath = PathUtil.getCanonicalPath(systemConfig.getDataDir() + "/"
-				+ EXAM_STUDENT_IMPORT_FILES + "/" + importEntity.getFilePath());
-		String resultFilePath = PathUtil.getCanonicalPath(systemConfig.getDataDir() + "/"
-				+ EXAM_STUDENT_IMPORT_FILES + "/" + importEntity.getResultFilePath());
-
-		File file = new File(destFilePath);
-
-		if (!file.exists()) {
-			importEntity.setStatus(ExamStudentImportStatus.ERROR);
-			importEntity.setErrorDesc("文件不存在");
-			examStudentImportRepo.saveAndFlush(importEntity);
-			return;
-		}
-
-		List<String[]> lineList = ExcelReader.readSheetBySax(PathUtil.getCanonicalPath(file), 1,
-				16);
-
-		if (CollectionUtils.isEmpty(lineList)) {
-			importEntity.setStatus(ExamStudentImportStatus.ERROR);
-			importEntity.setErrorDesc("Excel 没有内容");
-			examStudentImportRepo.saveAndFlush(importEntity);
-			return;
-		}
-
-		Long batchId = importEntity.getBatchId();
-		Long rootOrgId = importEntity.getRootOrgId();
-		Long examId = importEntity.getExamId();
-		List<ExamStudentTempEntity> list = Lists.newArrayList();
-
-		Set<String> fullSet = Sets.newHashSet();
-
-		List<Map<String, Object>> failRecords = Collections
-				.synchronizedList(new ArrayList<Map<String, Object>>());
-
-		StringBuilder sb = new StringBuilder();
-		sb.append("====================重复数据\n");
-		for (int i = 0; i < lineList.size(); i++) {
-			String[] line = lineList.get(i);
-			if (0 == i) {
-				if (headerError(line)) {
-					importEntity.setStatus(ExamStudentImportStatus.ERROR);
-					importEntity.setErrorDesc("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]));
-			String identityNumber = trimAndNullIfBlank(line[2]);
-			if (StringUtils.isNotBlank(identityNumber)) {
-				identityNumber = identityNumber.toUpperCase(Locale.US);
-			}
-			es.setIdentityNumber(identityNumber);
-			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]));
-
-			es.setExt1(trimAndNullIfBlank(line[13]));
-
-			String d1 = trimAndNullIfBlank(line[14]);
-			String d2 = trimAndNullIfBlank(line[15]);
-
-			if (!new Boolean(null == d1).equals(new Boolean(null == d2))) {
-				failRecords.add(buildFailRecord(es.getLineNum(), "考试时间不匹配"));
-				continue;
-			}
-
-			int trueNum = BooleanUtil.countTrue(null != d1, null != d2);
-			if (2 == trueNum) {
-				Date specialBeginTime = null;
-				Date specialEndTime = null;
-				try {
-					if (NumberUtils.isCreatable(d1)) {
-						specialBeginTime = DateUtil.parseExcel(d1);
-					} else {
-						specialBeginTime = DateUtil.parseRandomly(d1);
-					}
-				} catch (Exception e) {
-					failRecords.add(buildFailRecord(es.getLineNum(), "考试开始时间格式错误"));
-					continue;
-				}
-				try {
-					if (NumberUtils.isCreatable(d2)) {
-						specialEndTime = DateUtil.parseExcel(d2);
-					} else {
-						specialEndTime = DateUtil.parseRandomly(d2);
-					}
-				} catch (Exception e) {
-					failRecords.add(buildFailRecord(es.getLineNum(), "考试结束时间格式错误"));
-					continue;
-				}
-
-				if (specialBeginTime.after(specialEndTime)) {
-					failRecords.add(buildFailRecord(es.getLineNum(), "考试开始时间不能大于考试结束时间"));
-					continue;
-				}
-				es.setSpecialBeginTime(specialBeginTime);
-				es.setSpecialEndTime(specialEndTime);
-			}
-
-			if (hasError(failRecords, es)) {
-				continue;
-			}
-
-			list.add(es);
-			String key = es.getIdentityNumber() + "____" + es.getCourseCode();
-			if (fullSet.contains(key)) {
-				sb.append("line ").append(es.getLineNum()).append("  重复数据,执行更新").append("\n");
-			} else {
-				fullSet.add(key);
-			}
-			if (0 == i % 100) {
-				examStudentTempRepo.saveAll(list);
-
-				list = Lists.newArrayList();
-			}
-		}
-
-		examStudentTempRepo.saveAll(list);
-		sb.append("====================数据规格错误数据\n");
-		for (Map<String, Object> cur : failRecords) {
-			sb.append("line ").append(cur.get("lineNum")).append(cur.get("msg")).append("\n");
-		}
-
-		File resultFile = new File(resultFilePath);
-
-		try {
-			FileUtils.writeStringToFile(resultFile, sb.toString(), "UTF-8", true);
-		} catch (IOException e) {
-			importEntity.setStatus(ExamStudentImportStatus.ERROR);
-			importEntity.setErrorDesc("导入报告写入失败");
-			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) {
-			failRecords.add(buildFailRecord(entity.getLineNum(), sb.toString()));
-		}
-
-		return hasError;
-	}
-
-	/**
-	 * 构建错误信息
-	 *
-	 * @author WANGWEI
-	 * @param lineNum
-	 * @param msg
-	 * @return
-	 */
-	private Map<String, Object> buildFailRecord(Long lineNum, String msg) {
-		Map<String, Object> map = Maps.newHashMap();
-		map.put("lineNum", lineNum);
-		map.put("msg", msg);
-		return map;
-	}
-
-	/**
-	 * 方法注释
-	 *
-	 * @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 (null == header[i] || !EXCEL_HEADER[i].equals(header[i].trim())) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	@Override
-	public TaskTracker getTaskTracker() {
-		return taskTracker;
-	}
+    @Autowired
+    SystemProperties systemConfig;
+
+    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;
+
+    @Autowired
+    ExamStageCloudService examStageCloudService;
+
+    @Override
+    public void run(ScheduleJob scheduleJob) throws Exception {
+
+        ExamStudentImportEntity importEntity = examStudentImportRepo
+                .findFirstByStatusOrderByCreationTime(ExamStudentImportStatus.FILE_PARSING);
+
+        if (null == importEntity) {
+            importEntity = examStudentImportRepo
+                    .findFirstByStatusOrderByCreationTime(ExamStudentImportStatus.NONE);
+        }
+
+        if (null == importEntity) {
+            return;
+        }
+
+        importEntity.setStatus(ExamStudentImportStatus.FILE_PARSING);
+        examStudentImportRepo.saveAndFlush(importEntity);
+
+        try {
+            importExcel(importEntity);
+        } catch (Exception e) {
+            debugLog.error("文件解析异常", e);
+            importEntity.setStatus(ExamStudentImportStatus.ERROR);
+            importEntity.setErrorDesc("文件解析异常");
+            examStudentImportRepo.saveAndFlush(importEntity);
+            return;
+        }
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param importEntity
+     * @author WANGWEI
+     */
+    private void importExcel(ExamStudentImportEntity importEntity) {
+        String destFilePath = PathUtil.getCanonicalPath(systemConfig.getDataDir() + "/"
+                + EXAM_STUDENT_IMPORT_FILES + "/" + importEntity.getFilePath());
+        String resultFilePath = PathUtil.getCanonicalPath(systemConfig.getDataDir() + "/"
+                + EXAM_STUDENT_IMPORT_FILES + "/" + importEntity.getResultFilePath());
+
+        File file = new File(destFilePath);
+
+        if (!file.exists()) {
+            importEntity.setStatus(ExamStudentImportStatus.ERROR);
+            importEntity.setErrorDesc("文件不存在");
+            examStudentImportRepo.saveAndFlush(importEntity);
+            return;
+        }
+
+        List<String[]> lineList = ExcelReader.readSheetBySax(PathUtil.getCanonicalPath(file), 1,
+                EXCEL_HEADER.length);
+
+        if (CollectionUtils.isEmpty(lineList)) {
+            importEntity.setStatus(ExamStudentImportStatus.ERROR);
+            importEntity.setErrorDesc("Excel 没有内容");
+            examStudentImportRepo.saveAndFlush(importEntity);
+            return;
+        }
+
+        Long batchId = importEntity.getBatchId();
+        Long rootOrgId = importEntity.getRootOrgId();
+        Long examId = importEntity.getExamId();
+        List<ExamStudentTempEntity> list = Lists.newArrayList();
+
+        Set<String> fullSet = Sets.newHashSet();
+
+        List<Map<String, Object>> failRecords = Collections
+                .synchronizedList(new ArrayList<Map<String, Object>>());
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("====================重复数据\n");
+        for (int i = 0; i < lineList.size(); i++) {
+            String[] line = lineList.get(i);
+            if (0 == i) {
+                if (headerError(line)) {
+                    importEntity.setStatus(ExamStudentImportStatus.ERROR);
+                    importEntity.setErrorDesc("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]));
+            String identityNumber = trimAndNullIfBlank(line[2]);
+            if (StringUtils.isNotBlank(identityNumber)) {
+                identityNumber = identityNumber.toUpperCase(Locale.US);
+            }
+            es.setIdentityNumber(identityNumber);
+            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]));
+
+            es.setExt1(trimAndNullIfBlank(line[13]));
+
+            String d1 = trimAndNullIfBlank(line[14]);
+            String d2 = trimAndNullIfBlank(line[15]);
+
+            if (!new Boolean(null == d1).equals(new Boolean(null == d2))) {
+                failRecords.add(buildFailRecord(es.getLineNum(), "考试时间不匹配"));
+                continue;
+            }
+
+            int trueNum = BooleanUtil.countTrue(null != d1, null != d2);
+            if (2 == trueNum) {
+                Date specialBeginTime = null;
+                Date specialEndTime = null;
+                try {
+                    if (NumberUtils.isCreatable(d1)) {
+                        specialBeginTime = DateUtil.parseExcel(d1);
+                    } else {
+                        specialBeginTime = DateUtil.parseRandomly(d1);
+                    }
+                } catch (Exception e) {
+                    failRecords.add(buildFailRecord(es.getLineNum(), "考试开始时间格式错误"));
+                    continue;
+                }
+                try {
+                    if (NumberUtils.isCreatable(d2)) {
+                        specialEndTime = DateUtil.parseExcel(d2);
+                    } else {
+                        specialEndTime = DateUtil.parseRandomly(d2);
+                    }
+                } catch (Exception e) {
+                    failRecords.add(buildFailRecord(es.getLineNum(), "考试结束时间格式错误"));
+                    continue;
+                }
+
+                if (specialBeginTime.after(specialEndTime)) {
+                    failRecords.add(buildFailRecord(es.getLineNum(), "考试开始时间不能大于考试结束时间"));
+                    continue;
+                }
+                es.setSpecialBeginTime(specialBeginTime);
+                es.setSpecialEndTime(specialEndTime);
+            }
+
+            String strExamStageOrder = trimAndNullIfBlank(line[16]);
+            if (StringUtils.isNotEmpty(strExamStageOrder)) {
+
+                //只有开启场次特殊设置的才会使用场次字段值
+                ExamSettingsCacheBean examSettings = CacheHelper.getExamSettings(examId);
+                if (null != examSettings.getSpecialSettingsEnabled() && examSettings.getSpecialSettingsEnabled()
+                        && null != examSettings.getSpecialSettingsType()
+                        && ExamSpecialSettingsType.STAGE_BASED == examSettings.getSpecialSettingsType()) {
+
+                    Integer examStageOrder = null;
+                    try {
+                        examStageOrder = Integer.valueOf(strExamStageOrder);
+                    } catch (Exception e) {
+                        failRecords.add(buildFailRecord(es.getLineNum(), String.format("场次号:%s格式不正确", examStageOrder)));
+                        continue;
+                    }
+
+                    GetExamStageReq gesReq = new GetExamStageReq();
+                    gesReq.setExamId(examId);
+                    gesReq.setExamStageOrder(examStageOrder);
+
+                    try {
+                        GetExamStageResp gesResp = examStageCloudService.getExamStage(gesReq);
+                        ExamStageBean examStageBean = gesResp.getExamStageBean();
+
+                        if (null == examStageBean) {
+                            failRecords.add(buildFailRecord(es.getLineNum(), String.format("找不到场次号为:%s的数据", examStageOrder)));
+                            continue;
+                        }
+
+                        es.setExamStageId(gesResp.getId());
+                        es.setExamStageOrder(examStageOrder);
+                    } catch (Exception e) {
+                        taskLog.error(e.getMessage());
+
+                        failRecords.add(buildFailRecord(es.getLineNum(), String.format("获取场次信息失败:%s的数据", examStageOrder)));
+                        continue;
+                    }
+                }
+            }
+
+            if (hasError(failRecords, es)) {
+                continue;
+            }
+
+            list.add(es);
+
+            String key = es.getIdentityNumber() + "____" + es.getCourseCode();
+            if (fullSet.contains(key)) {
+                sb.append("line ").append(es.getLineNum()).append("  重复数据,执行更新").append("\n");
+            } else {
+                fullSet.add(key);
+            }
+
+            if (0 == i % 100) {
+                examStudentTempRepo.saveAll(list);
+
+                list = Lists.newArrayList();
+            }
+        }
+
+        examStudentTempRepo.saveAll(list);
+        sb.append("====================数据规格错误数据\n");
+        for (Map<String, Object> cur : failRecords) {
+            sb.append("line ").append(cur.get("lineNum")).append(cur.get("msg")).append("\n");
+        }
+
+        File resultFile = new File(resultFilePath);
+
+        try {
+            FileUtils.writeStringToFile(resultFile, sb.toString(), "UTF-8", true);
+        } catch (IOException e) {
+            importEntity.setStatus(ExamStudentImportStatus.ERROR);
+            importEntity.setErrorDesc("导入报告写入失败");
+            examStudentImportRepo.saveAndFlush(importEntity);
+            return;
+        }
+
+        importEntity.setStatus(ExamStudentImportStatus.FILE_PARSING_COMPLETE);
+        examStudentImportRepo.saveAndFlush(importEntity);
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param failRecords
+     * @param entity
+     * @return
+     * @author WANGWEI
+     */
+    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) {
+            failRecords.add(buildFailRecord(entity.getLineNum(), sb.toString()));
+        }
+
+        return hasError;
+    }
+
+    /**
+     * 构建错误信息
+     *
+     * @param lineNum
+     * @param msg
+     * @return
+     * @author WANGWEI
+     */
+    private Map<String, Object> buildFailRecord(Long lineNum, String msg) {
+        Map<String, Object> map = Maps.newHashMap();
+        map.put("lineNum", lineNum);
+        map.put("msg", msg);
+        return map;
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param s
+     * @return
+     * @author WANGWEI
+     */
+    private String trimAndNullIfBlank(String s) {
+        if (StringUtils.isBlank(s)) {
+            return null;
+        }
+        return s.trim();
+    }
+
+    /**
+     * 方法注释
+     *
+     * @param header
+     * @author WANGWEI
+     */
+    private boolean headerError(String[] header) {
+        for (int i = 0; i < EXCEL_HEADER.length; i++) {
+            if (null == header[i] || !EXCEL_HEADER[i].equals(header[i].trim())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public TaskTracker getTaskTracker() {
+        return taskTracker;
+    }
 }

+ 4 - 0
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/ExamStudentOnlineCountTask.java

@@ -8,6 +8,10 @@ import cn.com.qmth.examcloud.web.task.AbstractTask;
 import cn.com.qmth.examcloud.web.task.ScheduleJob;
 import cn.com.qmth.examcloud.web.task.TaskTracker;
 
+/**在线考生
+ * @author chenken
+ *
+ */
 @Component("examStudentOnlineCountTask")
 public class ExamStudentOnlineCountTask extends AbstractTask {
 

+ 4 - 0
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/StudentCumulativeCountTask.java

@@ -8,6 +8,10 @@ import cn.com.qmth.examcloud.web.task.AbstractTask;
 import cn.com.qmth.examcloud.web.task.ScheduleJob;
 import cn.com.qmth.examcloud.web.task.TaskTracker;
 
+/**累计在线学生
+ * @author chenken
+ *
+ */
 @Component("studentCumulativeCountTask")
 public class StudentCumulativeCountTask extends AbstractTask {
 

+ 4 - 0
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/StudentOnlineCountTask.java

@@ -8,6 +8,10 @@ import cn.com.qmth.examcloud.web.task.AbstractTask;
 import cn.com.qmth.examcloud.web.task.ScheduleJob;
 import cn.com.qmth.examcloud.web.task.TaskTracker;
 
+/**在线学生
+ * @author chenken
+ *
+ */
 @Component("studentOnlineCountTask")
 public class StudentOnlineCountTask extends AbstractTask {
 

+ 33 - 0
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/StudentOperateLogTask.java

@@ -0,0 +1,33 @@
+package cn.com.qmth.examcloud.task.service.job;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import cn.com.qmth.examcloud.core.reports.api.StudentOperateLogCloudService;
+import cn.com.qmth.examcloud.web.task.AbstractTask;
+import cn.com.qmth.examcloud.web.task.ScheduleJob;
+import cn.com.qmth.examcloud.web.task.TaskTracker;
+
+/**学生日志
+ * @author chenken
+ *
+ */
+@Component("studentOperateLogTask")
+public class StudentOperateLogTask extends AbstractTask {
+
+	@Autowired
+	StudentOperateLogCloudService studentOperateLogCloudService;
+
+	@Autowired
+	TaskTracker TaskTracker;
+	
+	@Override
+	public void run(ScheduleJob scheduleJob) throws Exception {
+		studentOperateLogCloudService.clean();
+	}
+
+	@Override
+	public TaskTracker getTaskTracker() {
+		return TaskTracker;
+	}
+}

+ 4 - 0
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/StudentTotalCountTask.java

@@ -29,6 +29,10 @@ import cn.com.qmth.examcloud.web.task.AbstractTask;
 import cn.com.qmth.examcloud.web.task.ScheduleJob;
 import cn.com.qmth.examcloud.web.task.TaskTracker;
 
+/**学生总数
+ * @author chenken
+ *
+ */
 @Component("studentTotalCountTask")
 public class StudentTotalCountTask extends AbstractTask {
 

+ 4 - 0
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/UserOnlineCountTask.java

@@ -8,6 +8,10 @@ import cn.com.qmth.examcloud.web.task.AbstractTask;
 import cn.com.qmth.examcloud.web.task.ScheduleJob;
 import cn.com.qmth.examcloud.web.task.TaskTracker;
 
+/**在线用户
+ * @author chenken
+ *
+ */
 @Component("userOnlineCountTask")
 public class UserOnlineCountTask extends AbstractTask {
 

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

@@ -1,6 +1,6 @@
 spring.profiles.active=dev
 
 examcloud.startup.startupCode=8007
-examcloud.startup.configCenterHost=127.0.0.1
+examcloud.startup.configCenterHost=192.168.10.39
 examcloud.startup.configCenterPort=9999
 examcloud.startup.appCode=T

+ 99 - 73
examcloud-task-starter/src/main/resources/log4j2.xml

@@ -1,82 +1,108 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Configuration status="WARN" monitorInterval="30">
 
-	<Properties>
-		<Property name="commonLevel" value="${sys:log.commonLevel}" />
-	</Properties>
+    <Properties>
+        <Property name="commonLevel" value="${sys:log.commonLevel}"/>
+        <Property name="logPattern">
+            %d{yyyy-MM-dd HH:mm:ss.SSS} | %clr{%level} | %X{TRACE_ID} %X{CALLER} | %clr{%c{1.1}:%L}{cyan} | %m%n
+        </Property>
+    </Properties>
 
-	<Appenders>
-		<!-- 控制台 日志 -->
-		<Console name="Console" target="SYSTEM_OUT">
-			<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}| %level | %X{TRACE_ID} - %X{CALLER} | %m | %l%n" />
-		</Console>
-		<!-- debug 日志 -->
-		<RollingFile name="DEBUG_APPERDER" fileName="./logs/debug/debug.log" filePattern="./logs/debug/debug-%d{yyyy.MM.dd.HH}-%i.log">
-			<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}| %level | %X{TRACE_ID} - %X{CALLER} | %m | %l%n" />
-			<Policies>
-				<TimeBasedTriggeringPolicy interval="1" />
-				<SizeBasedTriggeringPolicy size="100 MB" />
-			</Policies>
-			<DefaultRolloverStrategy max="10000">
-				<Delete basePath="./logs/debug" maxDepth="1">
-					<IfFileName glob="debug-*.log">
-						<IfAccumulatedFileSize exceeds="2 GB" />
-					</IfFileName>
-				</Delete>
-			</DefaultRolloverStrategy>
-		</RollingFile>
-		<!-- 接口日志 -->
-		<RollingFile name="INTERFACE_APPENDER" fileName="./logs/interface/interface.log" filePattern="./logs/interface/interface-%d{yyyy.MM.dd.HH}-%i.log">
-			<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}| %level | %X{TRACE_ID} - %X{CALLER} | %m%n" />
-			<Policies>
-				<TimeBasedTriggeringPolicy interval="1" />
-				<SizeBasedTriggeringPolicy size="100 MB" />
-			</Policies>
-			<DefaultRolloverStrategy max="10000">
-				<Delete basePath="./logs/interface" maxDepth="1">
-					<IfFileName glob="interface-*.log">
-						<IfAccumulatedFileSize exceeds="10 GB" />
-					</IfFileName>
-				</Delete>
-			</DefaultRolloverStrategy>
-		</RollingFile>
-		<!-- 任务日志 -->
-		<RollingFile name="TASK_APPENDER" fileName="./logs/task/task.log" filePattern="./logs/task/task-%d{yyyy.MM.dd.HH}-%i.log">
-			<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}| %level | %X{TRACE_ID} - %X{CALLER} | %m%n" />
-			<Policies>
-				<TimeBasedTriggeringPolicy interval="1" />
-				<SizeBasedTriggeringPolicy size="100 MB" />
-			</Policies>
-			<DefaultRolloverStrategy max="10000">
-				<Delete basePath="./logs/task" maxDepth="1">
-					<IfFileName glob="task-*.log">
-						<IfAccumulatedFileSize exceeds="2 GB" />
-					</IfFileName>
-				</Delete>
-			</DefaultRolloverStrategy>
-		</RollingFile>
-	</Appenders>
+    <Appenders>
+        <!-- 控制台 日志 -->
+        <Console name="Console" target="SYSTEM_OUT">
+            <PatternLayout pattern="${logPattern}" charset="UTF-8"/>
+        </Console>
 
-	<Loggers>
-		<Logger name="cn.com.qmth" level="${commonLevel}" additivity="false">
-			<AppenderRef ref="DEBUG_APPERDER" />
-			<AppenderRef ref="Console" />
-		</Logger>
+        <!-- debug 日志 -->
+        <RollingFile name="DEBUG_APPENDER"
+                     fileName="./logs/debug/debug.log"
+                     filePattern="./logs/debug/debug-%d{yyyy.MM.dd.HH}-%i.log">
+            <PatternLayout pattern="${logPattern}" charset="UTF-8"/>
+            <Policies>
+                <TimeBasedTriggeringPolicy interval="1" modulate="false"/>
+                <SizeBasedTriggeringPolicy size="100 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="1000">
+                <Delete basePath="./logs/debug" maxDepth="1">
+                    <IfFileName glob="debug-*.log">
+                        <IfAccumulatedFileSize exceeds="2 GB"/>
+                    </IfFileName>
+                </Delete>
+            </DefaultRolloverStrategy>
+        </RollingFile>
 
-		<Logger name="INTERFACE_LOGGER" level="INFO" additivity="false">
-			<AppenderRef ref="INTERFACE_APPENDER" />
-			<AppenderRef ref="Console" />
-		</Logger>
+        <!-- 接口日志 -->
+        <RollingFile name="INTERFACE_APPENDER" fileName="./logs/interface/interface.log"
+                     filePattern="./logs/interface/interface-%d{yyyy.MM.dd.HH}-%i.log">
+            <PatternLayout pattern="${logPattern}" charset="UTF-8"/>
+            <Policies>
+                <TimeBasedTriggeringPolicy interval="1" modulate="false"/>
+                <SizeBasedTriggeringPolicy size="100 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="1000">
+                <Delete basePath="./logs/interface" maxDepth="1">
+                    <IfFileName glob="interface-*.log">
+                        <IfAccumulatedFileSize exceeds="10 GB"/>
+                    </IfFileName>
+                </Delete>
+            </DefaultRolloverStrategy>
+        </RollingFile>
 
-		<Logger name="TASK_LOGGER" level="INFO" additivity="false">
-			<AppenderRef ref="TASK_APPENDER" />
-			<AppenderRef ref="Console" />
-		</Logger>
+        <!-- 任务日志 -->
+        <RollingFile name="TASK_APPENDER" fileName="./logs/task/task.log"
+                     filePattern="./logs/task/task-%d{yyyy.MM.dd.HH}-%i.log">
+            <PatternLayout pattern="${logPattern}" charset="UTF-8"/>
+            <Policies>
+                <TimeBasedTriggeringPolicy interval="1" modulate="false"/>
+                <SizeBasedTriggeringPolicy size="100 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="1000">
+                <Delete basePath="./logs/task" maxDepth="1">
+                    <IfFileName glob="task-*.log">
+                        <IfAccumulatedFileSize exceeds="2 GB"/>
+                    </IfFileName>
+                </Delete>
+            </DefaultRolloverStrategy>
+        </RollingFile>
+    </Appenders>
 
-		<Root level="INFO">
-			<AppenderRef ref="Console" />
-			<AppenderRef ref="DEBUG_APPERDER" />
-		</Root>
-	</Loggers>
+    <Loggers>
+        <logger name="springfox.documentation" level="ERROR"/>
+        <logger name="org.springframework" level="ERROR"/>
+        <logger name="org.hibernate" level="ERROR"/>
+        <logger name="org.apache" level="ERROR"/>
+        <logger name="org.quartz" level="ERROR"/>
+        <logger name="org.docx4j" level="ERROR"/>
+        <logger name="cn.afterturn" level="ERROR"/>
+        <logger name="com.netflix" level="ERROR"/>
+        <logger name="com.aliyun" level="ERROR"/>
+        <logger name="io.lettuce" level="ERROR"/>
+        <logger name="io.netty" level="ERROR"/>
 
-</Configuration>
+        <!--<logger name="org.springframework.jdbc.core.JdbcTemplate" level="DEBUG"/>-->
+        <!--<logger name="org.springframework.data.mongodb" level="DEBUG"/>-->
+        <!--<logger name="org.springframework.data.redis" level="DEBUG"/>-->
+
+        <Logger name="cn.com.qmth" level="${commonLevel}" additivity="false">
+            <AppenderRef ref="DEBUG_APPENDER"/>
+            <AppenderRef ref="Console"/>
+        </Logger>
+
+        <Logger name="INTERFACE_LOGGER" level="${commonLevel}" additivity="false">
+            <AppenderRef ref="INTERFACE_APPENDER"/>
+            <AppenderRef ref="Console"/>
+        </Logger>
+
+        <Logger name="TASK_LOGGER" level="${commonLevel}" additivity="false">
+            <AppenderRef ref="TASK_APPENDER"/>
+            <AppenderRef ref="Console"/>
+        </Logger>
+
+        <Root level="${commonLevel}">
+            <AppenderRef ref="Console"/>
+            <AppenderRef ref="DEBUG_APPENDER"/>
+        </Root>
+    </Loggers>
+
+</Configuration>

+ 0 - 19
jenkins-dev.sh

@@ -1,19 +0,0 @@
-#!/bin/bash
-pwd
-
-rm -rf ~/project/examcloud/examcloud-task-distribution.zip
-rm -rf ~/project/examcloud/examcloud-task/lib/
-rm -rf ~/project/examcloud/examcloud-task/config/
-
-cp examcloud-task-starter/target/examcloud-task-distribution.zip ~/project/examcloud/
-
-cd  ~/project/examcloud/
-unzip -o examcloud-task-distribution.zip
-
-cd examcloud-task
-echo "--spring.profiles.active=dev --examcloud.startup.configCenterHost=localhost" > start.args
-echo "-server -Xms512m -Xmx512m  -XX:-UseGCOverheadLimit" > start.vmoptions
-
-bash stop.sh
-BUILD_ID=DONTKILLME
-bash start.sh jenkins

+ 0 - 19
jenkins-test.sh

@@ -1,19 +0,0 @@
-#!/bin/bash
-pwd
-
-rm -rf ~/project/examcloud/examcloud-task-distribution.zip
-rm -rf ~/project/examcloud/examcloud-task/lib/
-rm -rf ~/project/examcloud/examcloud-task/config/
-
-cp examcloud-task-starter/target/examcloud-task-distribution.zip ~/project/examcloud/
-
-cd  ~/project/examcloud/
-unzip -o examcloud-task-distribution.zip
-
-cd examcloud-task
-echo "--spring.profiles.active=test --examcloud.startup.configCenterHost=localhost" > start.args
-echo "-server -Xms512m -Xmx512m  -XX:-UseGCOverheadLimit" > start.vmoptions
-
-bash stop.sh
-BUILD_ID=DONTKILLME
-bash start.sh jenkins