xiatian 9 månader sedan
förälder
incheckning
e1fbf22797

+ 32 - 0
src/main/java/cn/com/qmth/scancentral/consumer/AnswerDataExportConsumer.java

@@ -0,0 +1,32 @@
+package cn.com.qmth.scancentral.consumer;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.scancentral.service.SubjectService;
+import cn.com.qmth.scancentral.vo.subject.DataExportTaskVo;
+
+@Scope("prototype")
+@Service
+public class AnswerDataExportConsumer implements Runnable {
+
+    private DataExportTaskVo vo;
+
+    @Autowired
+    private SubjectService subjectService;
+
+    @Override
+    public void run() {
+        subjectService.answerDataExportDispose(vo);
+    }
+
+    public DataExportTaskVo getVo() {
+        return vo;
+    }
+
+    public void setVo(DataExportTaskVo vo) {
+        this.vo = vo;
+    }
+
+}

+ 7 - 0
src/main/java/cn/com/qmth/scancentral/controller/admin/SubjectController.java

@@ -16,6 +16,7 @@ import cn.com.qmth.scancentral.service.SubjectService;
 import cn.com.qmth.scancentral.vo.subject.ScanProgressVo;
 import cn.com.qmth.scancentral.vo.subject.SubjectBreachVo;
 import cn.com.qmth.scancentral.vo.subject.SubjectCustStatusVo;
+import cn.com.qmth.scancentral.vo.subject.TaskIdVo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 
@@ -45,4 +46,10 @@ public class SubjectController extends BaseController {
     public List<SubjectCustStatusVo> custStatusList(@RequestParam Long examId) {
         return subjectService.custStatusList(examId);
     }
+
+    @ApiOperation(value = "导出扫描答案DBF")
+    @PostMapping("answer-data/export")
+    public TaskIdVo answerDataExport(@RequestParam Long examId, @RequestParam String subjectCode) {
+        return subjectService.answerDataExport(examId, subjectCode);
+    }
 }

+ 15 - 0
src/main/java/cn/com/qmth/scancentral/service/DataExportTaskService.java

@@ -0,0 +1,15 @@
+package cn.com.qmth.scancentral.service;
+
+import cn.com.qmth.scancentral.vo.subject.DataExportTaskVo;
+
+public interface DataExportTaskService {
+
+    void clearTimeOut();
+
+    DataExportTaskVo getTask(String taskId);
+
+    void updateTaskActive(String taskId);
+
+    void addTask(DataExportTaskVo vo);
+
+}

+ 4 - 0
src/main/java/cn/com/qmth/scancentral/service/MarkSiteService.java

@@ -1,5 +1,7 @@
 package cn.com.qmth.scancentral.service;
 
+import java.util.List;
+
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.qmth.boot.core.collection.PageResult;
 
@@ -17,4 +19,6 @@ public interface MarkSiteService extends IService<MarkSiteEntity> {
 
     void delete(Long id);
 
+    List<MarkSiteEntity> findByExam(Long examId);
+
 }

+ 6 - 0
src/main/java/cn/com/qmth/scancentral/service/SubjectService.java

@@ -10,9 +10,11 @@ import cn.com.qmth.scancentral.bean.User;
 import cn.com.qmth.scancentral.entity.SubjectEntity;
 import cn.com.qmth.scancentral.vo.SubjectConfigVo;
 import cn.com.qmth.scancentral.vo.examinfo.SubjectConfig;
+import cn.com.qmth.scancentral.vo.subject.DataExportTaskVo;
 import cn.com.qmth.scancentral.vo.subject.ScanProgressVo;
 import cn.com.qmth.scancentral.vo.subject.SubjectBreachVo;
 import cn.com.qmth.scancentral.vo.subject.SubjectCustStatusVo;
+import cn.com.qmth.scancentral.vo.subject.TaskIdVo;
 
 public interface SubjectService extends IMppService<SubjectEntity> {
 
@@ -36,4 +38,8 @@ public interface SubjectService extends IMppService<SubjectEntity> {
 
     List<SubjectCustStatusVo> custStatusList(Long examId);
 
+    TaskIdVo answerDataExport(Long examId, String subjectCode);
+
+    void answerDataExportDispose(DataExportTaskVo vo);
+
 }

+ 56 - 0
src/main/java/cn/com/qmth/scancentral/service/impl/DataExportTaskServiceImpl.java

@@ -0,0 +1,56 @@
+package cn.com.qmth.scancentral.service.impl;
+
+import java.io.File;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.scancentral.service.DataExportTaskService;
+import cn.com.qmth.scancentral.vo.subject.DataExportTaskVo;
+
+@Service
+public class DataExportTaskServiceImpl implements DataExportTaskService {
+
+    // 30分钟
+    private static long timeOut = 30 * 60 * 1000;
+
+    private final static Map<String, DataExportTaskVo> tasks = new ConcurrentHashMap<>();
+
+    private final static Map<String, Long> taskActive = new ConcurrentHashMap<>();
+
+    @Override
+    public void addTask(DataExportTaskVo vo) {
+        tasks.put(vo.getTaskId(), vo);
+        taskActive.put(vo.getTaskId(), System.currentTimeMillis());
+    }
+
+    @Override
+    public void updateTaskActive(String taskId) {
+        taskActive.put(taskId, System.currentTimeMillis());
+    }
+
+    @Override
+    public void clearTimeOut() {
+        Long now = System.currentTimeMillis();
+        for (String k : taskActive.keySet()) {
+            if (now - taskActive.get(k) > timeOut) {
+                DataExportTaskVo vo = tasks.get(k);
+                if (vo != null) {
+                    if (vo.getFilePath() != null) {
+                        File f = new File(vo.getFilePath());
+                        f.delete();
+                    }
+                    tasks.remove(k);
+                }
+                tasks.remove(k);
+            }
+        }
+    }
+
+    @Override
+    public DataExportTaskVo getTask(String taskId) {
+        return tasks.get(taskId);
+    }
+
+}

+ 10 - 0
src/main/java/cn/com/qmth/scancentral/service/impl/MarkSiteServiceImpl.java

@@ -1,5 +1,7 @@
 package cn.com.qmth.scancentral.service.impl;
 
+import java.util.List;
+
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -85,4 +87,12 @@ public class MarkSiteServiceImpl extends ServiceImpl<MarkSiteDao, MarkSiteEntity
         this.delete(id);
     }
 
+    @Override
+    public List<MarkSiteEntity> findByExam(Long examId) {
+        QueryWrapper<MarkSiteEntity> wrapper = new QueryWrapper<>();
+        LambdaQueryWrapper<MarkSiteEntity> lw = wrapper.lambda();
+        lw.eq(MarkSiteEntity::getExamId, examId);
+        return this.list(wrapper);
+    }
+
 }

+ 174 - 0
src/main/java/cn/com/qmth/scancentral/service/impl/SubjectServiceImpl.java

@@ -1,5 +1,8 @@
 package cn.com.qmth.scancentral.service.impl;
 
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.HashMap;
@@ -7,8 +10,14 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -17,29 +26,44 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
 import com.qmth.boot.core.exception.ParameterException;
+import com.qmth.boot.core.exception.StatusException;
 import com.qmth.boot.core.fss.store.FileStore;
+import com.qmth.boot.tools.uuid.FastUUID;
 
 import cn.com.qmth.scancentral.bean.ImportSubjectDomain;
 import cn.com.qmth.scancentral.bean.SubjectConfigDomain;
 import cn.com.qmth.scancentral.bean.User;
+import cn.com.qmth.scancentral.consumer.AnswerDataExportConsumer;
 import cn.com.qmth.scancentral.dao.SubjectDao;
+import cn.com.qmth.scancentral.entity.MarkSiteEntity;
 import cn.com.qmth.scancentral.entity.SubjectEntity;
+import cn.com.qmth.scancentral.enums.ExamStatus;
 import cn.com.qmth.scancentral.service.BatchPaperService;
+import cn.com.qmth.scancentral.service.DataExportTaskService;
 import cn.com.qmth.scancentral.service.FileService;
+import cn.com.qmth.scancentral.service.MarkSiteService;
 import cn.com.qmth.scancentral.service.StudentService;
 import cn.com.qmth.scancentral.service.SubjectService;
+import cn.com.qmth.scancentral.support.SpringContextHolder;
 import cn.com.qmth.scancentral.util.Calculator;
 import cn.com.qmth.scancentral.util.FileUtil;
+import cn.com.qmth.scancentral.vo.ExportCetMarkingQueryVo;
+import cn.com.qmth.scancentral.vo.ExportCetVo;
+import cn.com.qmth.scancentral.vo.ImportStudentQueryVo;
 import cn.com.qmth.scancentral.vo.SubjectConfigVo;
 import cn.com.qmth.scancentral.vo.examinfo.SubjectConfig;
+import cn.com.qmth.scancentral.vo.subject.DataExportTaskVo;
 import cn.com.qmth.scancentral.vo.subject.ScanProgressVo;
 import cn.com.qmth.scancentral.vo.subject.SubjectBreachVo;
 import cn.com.qmth.scancentral.vo.subject.SubjectCustStatusVo;
 import cn.com.qmth.scancentral.vo.subject.SubjectScanProgressVo;
+import cn.com.qmth.scancentral.vo.subject.TaskIdVo;
 
 @Service
 public class SubjectServiceImpl extends MppServiceImpl<SubjectDao, SubjectEntity> implements SubjectService {
 
+    private static ExecutorService exec;
+
     @Autowired
     private StudentService studentService;
 
@@ -52,6 +76,29 @@ public class SubjectServiceImpl extends MppServiceImpl<SubjectDao, SubjectEntity
     @Autowired
     private BatchPaperService batchPaperService;
 
+    @Autowired
+    private DataExportTaskService dataExportTaskService;
+
+    @Autowired
+    private MarkSiteService markSiteService;
+
+    static {
+        int threadCount = 5;
+        exec = new ThreadPoolExecutor(threadCount, threadCount, 0L, TimeUnit.SECONDS,
+                new LinkedBlockingQueue<>(threadCount * 2), r -> {
+                    Thread t = new Thread(r);
+                    return t;
+                }, (r, executor) -> {
+                    if (!executor.isShutdown()) {
+                        try {
+                            executor.getQueue().put(r);
+                        } catch (InterruptedException e) {
+                            throw new RuntimeException(e);
+                        }
+                    }
+                });
+    }
+
     @Transactional
     @Override
     public int cleanByExamId(Long examId, String subjectCode) {
@@ -239,4 +286,131 @@ public class SubjectServiceImpl extends MppServiceImpl<SubjectDao, SubjectEntity
         return ret;
     }
 
+    @Override
+    public TaskIdVo answerDataExport(Long examId, String subjectCode) {
+        ImportStudentQueryVo sreq = new ImportStudentQueryVo();
+        sreq.setExamId(examId);
+        int scount = studentService.countByQuery(sreq);
+        if (scount == 0) {
+            throw new StatusException("没有考生信息");
+        }
+        DataExportTaskVo vo = new DataExportTaskVo();
+        vo.setExamId(examId);
+        vo.setSubjectCode(subjectCode);
+        vo.setSuccess(true);
+        vo.setProgress(0.0);
+        vo.setFileName("扫描答案.dbf");
+        AnswerDataExportConsumer com = SpringContextHolder.getBean(AnswerDataExportConsumer.class);
+        com.setVo(vo);
+        exec.execute(com);
+        dataExportTaskService.addTask(vo);
+        return TaskIdVo.create(vo.getTaskId());
+    }
+
+    @Override
+    public void answerDataExportDispose(DataExportTaskVo vo) {
+        File temDir = new File("temp/" + FastUUID.get() + "/");
+        temDir.mkdirs();
+        ExportCetMarkingQueryVo req = new ExportCetMarkingQueryVo();
+        req.setExamId(vo.getExamId());
+        req.setPageSize(100000);
+        int pageNumber = 0;
+        req.setPageNumber(pageNumber);
+        Set<String> examNumbers = new HashSet<>();
+        Map<String, MarkSiteEntity> cms = readCetMarking(vo.getExamId());
+        while (true) {
+            req.setPageNumber(++pageNumber);
+            List<ExportCetVo> list = studentService.exportCetData(req);
+            if (CollectionUtils.isEmpty(list)) {
+                break;
+            }
+            exportAnswer(examNumbers, temDir, list, cms);
+        }
+    }
+
+    private void exportAnswer(Set<String> examNumbers, File temDir, List<ExportCetVo> list,
+            Map<String, MarkSiteEntity> cms) {
+        Map<String, List<String>> subjects = new HashMap<>();
+        for (ExportCetVo data : list) {
+            String key = data.getSubjectCode() + "-" + data.getExamNumber();
+            if (examNumbers.contains(key)) {
+                continue;
+            }
+            examNumbers.add(key);
+            List<String> line = new ArrayList<>();
+            line.add(data.getExamNumber());
+            line.add(data.getName());
+            if (ExamStatus.ABSENT.equals(data.getExamStatus())) {
+                line.add("1");
+            } else {
+                line.add("0");
+            }
+            line.add(data.getSubjectCode());
+            line.add(data.getAnswer());
+            line.add(data.getCardFirst() + "");
+            line.add(data.getCardSecond() + "");
+            line.add(StringUtils.isBlank(data.getBreachCode()) ? "0" : data.getBreachCode());
+            line.add(data.getPaperType());
+            int subjectCode = Integer.valueOf(data.getExamNumber().substring(9, 10));
+            String markingCode;
+            if (subjectCode >= 3 && subjectCode <= 9) {
+                markingCode = "88";
+            } else {
+                if (ExamStatus.ABSENT.equals(data.getExamStatus()) || "000000".equals(data.getPaperType())
+                        || "999999".equals(data.getPaperType())) {
+                    markingCode = "00";
+                } else {
+                    int site = Integer.valueOf(data.getExamNumber().substring(10, 13));
+                    MarkSiteEntity cm = cms.get(data.getSubjectCode() + "-" + data.getPaperType());
+                    if (cm == null) {
+                        throw new StatusException(
+                                "未找到评卷点数据,SubjectCode:" + data.getSubjectCode() + " PaperType:" + data.getPaperType());
+                    }
+                    if (site % 2 == 0) {
+                        markingCode = cm.getEvenNumber();
+                    } else {
+                        markingCode = cm.getOddNumber();
+                    }
+                }
+            }
+            line.add(markingCode);
+            List<String> lines = subjects.get(data.getSubjectCode());
+            if (lines == null) {
+                lines = new ArrayList<>();
+                subjects.put(data.getSubjectCode(), lines);
+            }
+            lines.add(StringUtils.join(line, ","));
+        }
+        writeResult(subjects, temDir, "answer-data.txt");
+    }
+
+    private void writeResult(Map<String, List<String>> subjects, File rootDir, String fileName) {
+        for (String k : subjects.keySet()) {
+            File file = new File(rootDir.getAbsolutePath() + "/" + k + "/" + fileName);
+            file.getParentFile().mkdirs();
+            if (!file.exists()) {
+                try {
+                    file.createNewFile();
+                } catch (IOException e) {
+                    throw new StatusException("", e);
+                }
+            }
+            try {
+                FileUtils.writeLines(file, StandardCharsets.UTF_8.name(), subjects.get(k), true);
+            } catch (IOException e) {
+                throw new StatusException("文件处理出错", e);
+            }
+        }
+    }
+
+    private Map<String, MarkSiteEntity> readCetMarking(Long examId) {
+        Map<String, MarkSiteEntity> ret = new HashMap<>();
+        List<MarkSiteEntity> list = markSiteService.findByExam(examId);
+        if (CollectionUtils.isNotEmpty(list)) {
+            for (MarkSiteEntity e : list) {
+                ret.put(e.getSubjectCode() + "-" + e.getPaperType(), e);
+            }
+        }
+        return ret;
+    }
 }

+ 20 - 0
src/main/java/cn/com/qmth/scancentral/task/DataExportTaskJob.java

@@ -0,0 +1,20 @@
+package cn.com.qmth.scancentral.task;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import cn.com.qmth.scancentral.service.DataExportTaskService;
+
+@Service
+public class DataExportTaskJob {
+
+    @Autowired
+    private DataExportTaskService dataExportTaskService;
+
+    @Scheduled(fixedDelay = 30 * 1000, initialDelay = 30 * 1000)
+    public void run() {
+        dataExportTaskService.clearTimeOut();
+    }
+
+}

+ 1 - 1
src/main/java/cn/com/qmth/scancentral/task/OnlineUserCountJob.java

@@ -11,7 +11,7 @@ public class OnlineUserCountJob {
     @Autowired
     private SessionService sessionService;
 
-    @Scheduled(cron = "0/30 * * * * ?")
+    @Scheduled(fixedDelay = 15 * 1000, initialDelay = 30 * 1000)
     public void run() {
         sessionService.clearTimeOutUser();
     }

+ 35 - 0
src/main/java/cn/com/qmth/scancentral/vo/subject/DataExportProgressVo.java

@@ -0,0 +1,35 @@
+package cn.com.qmth.scancentral.vo.subject;
+
+public class DataExportProgressVo {
+
+    private Double progress;
+
+    private Boolean success;
+
+    private String errMsg;
+
+    public Double getProgress() {
+        return progress;
+    }
+
+    public void setProgress(Double progress) {
+        this.progress = progress;
+    }
+
+    public Boolean getSuccess() {
+        return success;
+    }
+
+    public void setSuccess(Boolean success) {
+        this.success = success;
+    }
+
+    public String getErrMsg() {
+        return errMsg;
+    }
+
+    public void setErrMsg(String errMsg) {
+        this.errMsg = errMsg;
+    }
+
+}

+ 85 - 0
src/main/java/cn/com/qmth/scancentral/vo/subject/DataExportTaskVo.java

@@ -0,0 +1,85 @@
+package cn.com.qmth.scancentral.vo.subject;
+
+public class DataExportTaskVo {
+
+    private String taskId;
+
+    private Long examId;
+
+    private String subjectCode;
+
+    private Double progress;
+
+    private Boolean success;
+
+    private String errMsg;
+
+    private String filePath;
+
+    private String fileName;
+
+    public String getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(String taskId) {
+        this.taskId = taskId;
+    }
+
+    public Double getProgress() {
+        return progress;
+    }
+
+    public void setProgress(Double progress) {
+        this.progress = progress;
+    }
+
+    public String getFilePath() {
+        return filePath;
+    }
+
+    public void setFilePath(String filePath) {
+        this.filePath = filePath;
+    }
+
+    public Boolean getSuccess() {
+        return success;
+    }
+
+    public void setSuccess(Boolean success) {
+        this.success = success;
+    }
+
+    public String getErrMsg() {
+        return errMsg;
+    }
+
+    public void setErrMsg(String errMsg) {
+        this.errMsg = errMsg;
+    }
+
+    public Long getExamId() {
+        return examId;
+    }
+
+    public void setExamId(Long examId) {
+        this.examId = examId;
+    }
+
+    public String getSubjectCode() {
+        return subjectCode;
+    }
+
+    public void setSubjectCode(String subjectCode) {
+        this.subjectCode = subjectCode;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+
+}

+ 21 - 0
src/main/java/cn/com/qmth/scancentral/vo/subject/TaskIdVo.java

@@ -0,0 +1,21 @@
+package cn.com.qmth.scancentral.vo.subject;
+
+public class TaskIdVo {
+
+    private String taskId;
+
+    public static TaskIdVo create(String taskId) {
+        TaskIdVo vo = new TaskIdVo();
+        vo.setTaskId(taskId);
+        return vo;
+    }
+
+    public String getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(String taskId) {
+        this.taskId = taskId;
+    }
+
+}