|
@@ -1,12 +1,9 @@
|
|
package cn.com.qmth.scancentral.service.impl;
|
|
package cn.com.qmth.scancentral.service.impl;
|
|
|
|
|
|
import cn.com.qmth.scancentral.bean.ImportStudentDomain;
|
|
import cn.com.qmth.scancentral.bean.ImportStudentDomain;
|
|
-import cn.com.qmth.scancentral.entity.ExamEntity;
|
|
|
|
-import cn.com.qmth.scancentral.service.ExamService;
|
|
|
|
import cn.com.qmth.scancentral.service.StudentImportService;
|
|
import cn.com.qmth.scancentral.service.StudentImportService;
|
|
import cn.com.qmth.scancentral.service.StudentService;
|
|
import cn.com.qmth.scancentral.service.StudentService;
|
|
import cn.com.qmth.scancentral.service.SubjectService;
|
|
import cn.com.qmth.scancentral.service.SubjectService;
|
|
-import cn.com.qmth.scancentral.util.FileUtil;
|
|
|
|
import cn.com.qmth.scancentral.vo.studentimport.ImportTaskVo;
|
|
import cn.com.qmth.scancentral.vo.studentimport.ImportTaskVo;
|
|
import cn.com.qmth.scancentral.vo.studentimport.StudentImportInfo;
|
|
import cn.com.qmth.scancentral.vo.studentimport.StudentImportInfo;
|
|
import com.qmth.boot.core.exception.ParameterException;
|
|
import com.qmth.boot.core.exception.ParameterException;
|
|
@@ -31,9 +28,6 @@ public class StudentImportServiceImpl implements StudentImportService {
|
|
|
|
|
|
private final static Map<String, ImportTaskVo> IMPORT_TASKS = new ConcurrentHashMap<>();
|
|
private final static Map<String, ImportTaskVo> IMPORT_TASKS = new ConcurrentHashMap<>();
|
|
|
|
|
|
- @Autowired
|
|
|
|
- private ExamService examService;
|
|
|
|
-
|
|
|
|
@Autowired
|
|
@Autowired
|
|
private SubjectService subjectService;
|
|
private SubjectService subjectService;
|
|
|
|
|
|
@@ -41,43 +35,18 @@ public class StudentImportServiceImpl implements StudentImportService {
|
|
private StudentService studentService;
|
|
private StudentService studentService;
|
|
|
|
|
|
@Override
|
|
@Override
|
|
- public Map<String, Object> studentImportProgress(String taskId) {
|
|
|
|
|
|
+ public ImportTaskVo studentImportProgress(String taskId) {
|
|
ImportTaskVo task = IMPORT_TASKS.get(taskId);
|
|
ImportTaskVo task = IMPORT_TASKS.get(taskId);
|
|
if (task == null) {
|
|
if (task == null) {
|
|
throw new ParameterException("考生导入任务不存在");
|
|
throw new ParameterException("考生导入任务不存在");
|
|
}
|
|
}
|
|
-
|
|
|
|
- Map<String, Object> result = new HashMap<>();
|
|
|
|
- result.put("progress", task.getProgress());
|
|
|
|
- if (task.getProgress() == 100d) {
|
|
|
|
- result.put("logFileUrl", "/api/admin/student/import/report/" + taskId);
|
|
|
|
- }
|
|
|
|
- return result;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- public File studentImportReport(String taskId) {
|
|
|
|
- ImportTaskVo task = IMPORT_TASKS.get(taskId);
|
|
|
|
- if (task == null) {
|
|
|
|
- throw new ParameterException("考生导入任务不存在");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (task.getProgress() != 100d) {
|
|
|
|
- throw new ParameterException("考生导入报告文件正在生成中");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- File logFile = new File(task.getLogFilePath());
|
|
|
|
- if (!logFile.exists()) {
|
|
|
|
- throw new ParameterException("考生导入报告文件不存在");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return logFile;
|
|
|
|
|
|
+ return task;
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public boolean existRunningStudentImportTask() {
|
|
public boolean existRunningStudentImportTask() {
|
|
for (ImportTaskVo task : IMPORT_TASKS.values()) {
|
|
for (ImportTaskVo task : IMPORT_TASKS.values()) {
|
|
- if (task.getProgress() < 100d) {
|
|
|
|
|
|
+ if (task.getRunning()) {
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -86,73 +55,27 @@ public class StudentImportServiceImpl implements StudentImportService {
|
|
|
|
|
|
@Async
|
|
@Async
|
|
@Override
|
|
@Override
|
|
- public void studentImport(String taskId, Long examId, String fileName, byte[] fileBytes) {
|
|
|
|
- final String tempDir = "temp/import_data/";
|
|
|
|
- FileUtil.makeDirs(tempDir);
|
|
|
|
- File logFile = new File(tempDir + taskId + ".log");
|
|
|
|
-
|
|
|
|
|
|
+ public void studentImport(String taskId, List<String> lines, Long examId, Integer yearConfig, Integer yearHalfConfig) {
|
|
ImportTaskVo task = new ImportTaskVo();
|
|
ImportTaskVo task = new ImportTaskVo();
|
|
task.setTaskId(taskId);
|
|
task.setTaskId(taskId);
|
|
task.setProgress(0d);
|
|
task.setProgress(0d);
|
|
- task.setLogFilePath(logFile.getAbsolutePath());
|
|
|
|
|
|
+ task.setRunning(true);
|
|
IMPORT_TASKS.put(taskId, task);
|
|
IMPORT_TASKS.put(taskId, task);
|
|
|
|
|
|
- int total = 0, finishCount = 0;
|
|
|
|
-
|
|
|
|
|
|
+ List<StudentImportInfo> list = new ArrayList<>();
|
|
try {
|
|
try {
|
|
- ExamEntity exam = examService.getById(examId);
|
|
|
|
- if (exam == null) {
|
|
|
|
- this.writeLogFile(logFile, "【错误】当前考试不存在");
|
|
|
|
- task.setProgress(100d);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (exam.getYear() == null || exam.getYearHalf() == null) {
|
|
|
|
- this.writeLogFile(logFile, "【错误】未设置考试年度或考次");
|
|
|
|
- task.setProgress(100d);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- String fileSuffix = FileUtil.getFileSuffix(fileName);
|
|
|
|
- if (!".txt".equals(fileSuffix)) {
|
|
|
|
- this.writeLogFile(logFile, "【错误】导入模板目前仅支持后缀名为“.txt”的文件");
|
|
|
|
- task.setProgress(100d);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- List<String> lines;
|
|
|
|
- try {
|
|
|
|
- File dataFile = new File(tempDir + taskId + fileSuffix);
|
|
|
|
- FileUtils.writeByteArrayToFile(dataFile, fileBytes);
|
|
|
|
- lines = FileUtil.readAllLines(dataFile);
|
|
|
|
- log.warn("读取考生数据文件共{}行! taskId:{}", lines.size(), taskId);
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- log.error(e.getMessage());
|
|
|
|
- this.writeLogFile(logFile, "【错误】读取导入数据文件失败");
|
|
|
|
- task.setProgress(100d);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- List<StudentImportInfo> list = new ArrayList<>();
|
|
|
|
- List<String> errs = this.parseValues(lines, list, examId, exam.getYear(), exam.getYearHalf());
|
|
|
|
- log.warn("本次解析考生数据共{}条! errCount:{} taskId:{}", list.size(), errs.size(), taskId);
|
|
|
|
- if (!errs.isEmpty()) {
|
|
|
|
- errs.add(String.format("本次解析考生数据共%s条,执行导入0条,请先处理文件内容错误!", list.size()));
|
|
|
|
- this.writeLogFile(logFile, StringUtils.join(errs, "\n"));
|
|
|
|
- task.setProgress(100d);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (list.isEmpty()) {
|
|
|
|
- this.writeLogFile(logFile, "本次解析考生数据共0条,请填写有效的数据内容!");
|
|
|
|
- task.setProgress(100d);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- log.info("执行导入数据库开始... {}", taskId);
|
|
|
|
- this.writeLogFile(logFile, "执行导入数据库开始...");
|
|
|
|
|
|
+ this.parseValues(lines, list, examId, yearConfig, yearHalfConfig);
|
|
|
|
+ log.warn("【考生导入】解析考生数据,有效共{}条! taskId:{}", list.size(), taskId);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ log.error("【考生导入】解析考生数据错误! taskId:{} {}", taskId, e.getMessage());
|
|
|
|
+ task.setRunning(false);
|
|
|
|
+ task.setErrMsg(e.getMessage());
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
|
|
- total = list.size();
|
|
|
|
|
|
+ int total = list.size(), finishCount = 0;
|
|
|
|
+ try {
|
|
|
|
+ log.info("【考生导入】执行导入数据库开始... {}", taskId);
|
|
long startTime = System.currentTimeMillis();
|
|
long startTime = System.currentTimeMillis();
|
|
|
|
|
|
int batchNum = 1000;
|
|
int batchNum = 1000;
|
|
@@ -168,7 +91,7 @@ public class StudentImportServiceImpl implements StudentImportService {
|
|
|
|
|
|
double progress = finishCount * 100f / total;
|
|
double progress = finishCount * 100f / total;
|
|
long cost = (System.currentTimeMillis() - startTime) / 1000L;
|
|
long cost = (System.currentTimeMillis() - startTime) / 1000L;
|
|
- log.info("已导入:{}条 已耗时:{}秒 进度:{}%", finishCount, cost, progress);
|
|
|
|
|
|
+ log.info("【考生导入】共{}条 已导入:{}条 已耗时:{}秒 进度:{}%", total, finishCount, cost, progress);
|
|
task.setProgress(progress);
|
|
task.setProgress(progress);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -178,16 +101,14 @@ public class StudentImportServiceImpl implements StudentImportService {
|
|
finishCount = finishCount + batchList.size();
|
|
finishCount = finishCount + batchList.size();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ task.setProgress(100d);
|
|
long cost = (System.currentTimeMillis() - startTime) / 1000L;
|
|
long cost = (System.currentTimeMillis() - startTime) / 1000L;
|
|
- log.info("已导入:{}条 已耗时:{}秒 进度:100% taskId:{}", finishCount, cost, taskId);
|
|
|
|
- this.writeLogFile(logFile,
|
|
|
|
- String.format("本次解析考生数据共%s条,已导入%s条,未导入%s条!", total, finishCount, total - finishCount));
|
|
|
|
|
|
+ log.info("【考生导入】共{}条 已导入:{}条 已耗时:{}秒 进度:100% taskId:{}", total, finishCount, cost, taskId);
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
- log.error("导入过程异常终止,已导入{}条,未导入{}条!taskId:{} err:{}", finishCount, total - finishCount, taskId,
|
|
|
|
- e.getMessage(), e);
|
|
|
|
- this.writeLogFile(logFile, String.format("【错误】导入过程异常终止,已导入%s条,未导入%s条!", finishCount, total - finishCount));
|
|
|
|
|
|
+ task.setErrMsg(String.format("导入异常终止,已导入%s条,未导入%s条!", finishCount, total - finishCount));
|
|
|
|
+ log.error("【考生导入】导入异常终止,已导入{}条,未导入{}条!taskId:{} err:{}", finishCount, total - finishCount, taskId, e.getMessage(), e);
|
|
} finally {
|
|
} finally {
|
|
- task.setProgress(100d);
|
|
|
|
|
|
+ task.setRunning(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -208,11 +129,9 @@ public class StudentImportServiceImpl implements StudentImportService {
|
|
return data;
|
|
return data;
|
|
}
|
|
}
|
|
|
|
|
|
- private List<String> parseValues(List<String> lines, List<StudentImportInfo> list, Long examId, Integer yearConfig,
|
|
|
|
- Integer yearHalfConfig) {
|
|
|
|
|
|
+ private void parseValues(List<String> lines, List<StudentImportInfo> list, Long examId, Integer yearConfig, Integer yearHalfConfig) {
|
|
Set<String> subjectCodes = new HashSet<>();
|
|
Set<String> subjectCodes = new HashSet<>();
|
|
Set<String> examNumbers = new HashSet<>();
|
|
Set<String> examNumbers = new HashSet<>();
|
|
- List<String> errs = new ArrayList<>();
|
|
|
|
Pattern examNumberPattern = Pattern.compile("^[0-9]{15}$");
|
|
Pattern examNumberPattern = Pattern.compile("^[0-9]{15}$");
|
|
|
|
|
|
for (int n = 1; n < lines.size(); n++) {
|
|
for (int n = 1; n < lines.size(); n++) {
|
|
@@ -224,53 +143,40 @@ public class StudentImportServiceImpl implements StudentImportService {
|
|
line = StringUtils.deleteWhitespace(line);
|
|
line = StringUtils.deleteWhitespace(line);
|
|
String[] values = StringUtils.splitByWholeSeparatorPreserveAllTokens(line, ",");
|
|
String[] values = StringUtils.splitByWholeSeparatorPreserveAllTokens(line, ",");
|
|
if (values.length != 3) {
|
|
if (values.length != 3) {
|
|
- errs.add(String.format("【第%s行】数据格式不正确", n + 1));
|
|
|
|
- continue;
|
|
|
|
|
|
+ throw new RuntimeException(String.format("【第%s行】数据格式不正确", n + 1));
|
|
}
|
|
}
|
|
|
|
|
|
- boolean okData = true;
|
|
|
|
// 默认模板:准考证号,姓名,考点名称(标题行,数据从第二行读取)
|
|
// 默认模板:准考证号,姓名,考点名称(标题行,数据从第二行读取)
|
|
String examNumber = values[0].trim();
|
|
String examNumber = values[0].trim();
|
|
String name = values[1].trim();
|
|
String name = values[1].trim();
|
|
String examSiteName = values[2].trim();
|
|
String examSiteName = values[2].trim();
|
|
|
|
|
|
if (StringUtils.isEmpty(examNumber)) {
|
|
if (StringUtils.isEmpty(examNumber)) {
|
|
- okData = false;
|
|
|
|
- errs.add(String.format("【第%s行】准考证号不能为空", n + 1));
|
|
|
|
|
|
+ throw new RuntimeException(String.format("【第%s行】准考证号不能为空", n + 1));
|
|
}
|
|
}
|
|
if (StringUtils.isEmpty(name)) {
|
|
if (StringUtils.isEmpty(name)) {
|
|
- okData = false;
|
|
|
|
- errs.add(String.format("【第%s行】姓名不能为空", n + 1));
|
|
|
|
|
|
+ throw new RuntimeException(String.format("【第%s行】姓名不能为空", n + 1));
|
|
}
|
|
}
|
|
if (StringUtils.isEmpty(examSiteName)) {
|
|
if (StringUtils.isEmpty(examSiteName)) {
|
|
- okData = false;
|
|
|
|
- errs.add(String.format("【第%s行】考点名称不能为空", n + 1));
|
|
|
|
|
|
+ throw new RuntimeException(String.format("【第%s行】考点名称不能为空", n + 1));
|
|
}
|
|
}
|
|
if (examNumbers.contains(examNumber)) {
|
|
if (examNumbers.contains(examNumber)) {
|
|
- okData = false;
|
|
|
|
- errs.add(String.format("【第%s行】考生信息存在重复", n + 1));
|
|
|
|
|
|
+ throw new RuntimeException(String.format("【第%s行】考生信息存在重复", n + 1));
|
|
}
|
|
}
|
|
examNumbers.add(examNumber);
|
|
examNumbers.add(examNumber);
|
|
|
|
|
|
if (!examNumberPattern.matcher(examNumber).find()) {
|
|
if (!examNumberPattern.matcher(examNumber).find()) {
|
|
- errs.add(String.format("【第%s行】准考证号不是15位数字", n + 1));
|
|
|
|
- continue;
|
|
|
|
|
|
+ throw new RuntimeException(String.format("【第%s行】准考证号不是15位数字", n + 1));
|
|
}
|
|
}
|
|
|
|
|
|
String year = examNumber.substring(6, 8);
|
|
String year = examNumber.substring(6, 8);
|
|
if (!yearConfig.toString().equals(year)) {
|
|
if (!yearConfig.toString().equals(year)) {
|
|
- okData = false;
|
|
|
|
- errs.add(String.format("【第%s行】考试年度不正确", n + 1));
|
|
|
|
|
|
+ throw new RuntimeException(String.format("【第%s行】考试年度不正确", n + 1));
|
|
}
|
|
}
|
|
|
|
|
|
String yearHalf = examNumber.substring(8, 9);
|
|
String yearHalf = examNumber.substring(8, 9);
|
|
if (!yearHalfConfig.toString().equals(yearHalf)) {
|
|
if (!yearHalfConfig.toString().equals(yearHalf)) {
|
|
- okData = false;
|
|
|
|
- errs.add(String.format("【第%s行】考次不正确", n + 1));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!okData) {
|
|
|
|
- continue;
|
|
|
|
|
|
+ throw new RuntimeException(String.format("【第%s行】考次不正确", n + 1));
|
|
}
|
|
}
|
|
|
|
|
|
String province = examNumber.substring(0, 3);
|
|
String province = examNumber.substring(0, 3);
|
|
@@ -302,11 +208,9 @@ public class StudentImportServiceImpl implements StudentImportService {
|
|
for (String subjectCode : subjectCodes) {
|
|
for (String subjectCode : subjectCodes) {
|
|
if (subjectService.findByExamIdAndCode(examId, subjectCode) == null) {
|
|
if (subjectService.findByExamIdAndCode(examId, subjectCode) == null) {
|
|
log.warn("科目不存在!examId:{} subjectCode:{}", examId, subjectCode);
|
|
log.warn("科目不存在!examId:{} subjectCode:{}", examId, subjectCode);
|
|
- errs.add(String.format("【错误】科目代码不存在!subjectCode:%s", subjectCode));
|
|
|
|
|
|
+ throw new RuntimeException(String.format("科目代码【%s】不存在!", subjectCode));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- return errs;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
private void writeLogFile(File logFile, String content) {
|
|
private void writeLogFile(File logFile, String content) {
|