Ver Fonte

随考随阅

xiatian há 1 mês atrás
pai
commit
9b7e6f7c35

+ 144 - 0
examcloud-task-base/src/main/java/cn/com/qmth/examcloud/task/base/multithread/ResultProducer.java

@@ -0,0 +1,144 @@
+package cn.com.qmth.examcloud.task.base.multithread;
+
+import java.util.Map;
+
+import org.apache.logging.log4j.ThreadContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+
+public abstract class ResultProducer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ResultProducer.class);
+
+    private Basket basket;
+
+    /**
+     * 业务参数
+     */
+    private Map<String, Object> param;
+
+    /**
+     * 消费线程class
+     */
+    private Class<? extends Consumer<?>> consumer;
+
+    /**
+     * 处理开始方法
+     * 
+     * @param consumer
+     *            消费线程class
+     * @param consumerCount
+     *            消费线程数
+     * @param param
+     *            生产者业务参数
+     * @throws InstantiationException
+     * @throws IllegalAccessException
+     */
+    public Object startDispose(Class<? extends Consumer<?>> consumer, int consumerCount, Map<String, Object> param)
+            throws InstantiationException, IllegalAccessException {
+        Basket basket = new Basket(consumerCount);
+        this.basket = basket;
+        this.consumer = consumer;
+        this.param = param;
+        // 启动消费者
+        startConsumer();
+        // 开始处理
+        return dispose();
+    }
+
+    private Object dispose() {
+        try {
+            LOG.info("*******************Producer:开始处理");
+            // 生产数据
+            Object result = produce(param);
+            LOG.info("*******************Producer:生产结束");
+            // 发送生产结束信息
+            endConsumer();
+            LOG.info("*******************Producer:成功发送生产结束信息");
+            // 等待子线程结束
+            LOG.info("*******************Producer:等待消费线程结束");
+            await();
+            LOG.info("*******************Producer:消费线程已结束");
+            // 判断子线程是否正常结束
+            if (basket.isExcuteError()) {
+                throw new StatusException("1000001", "处理失败,线程异常");
+            }
+            LOG.info("*******************Producer:结束处理");
+            return result;
+        } catch (StatusException e) {
+            // 获取异常时发送异常结束信息
+            endConsumerAsError();
+            throw e;
+        } catch (Exception e) {
+            // 获取异常时发送异常结束信息
+            endConsumerAsError();
+            throw new StatusException("1000002", "处理失败", e);
+        }
+    }
+
+    /**
+     * 启动消费者
+     * 
+     * @param consumer
+     * @throws InstantiationException
+     * @throws IllegalAccessException
+     */
+    private void startConsumer() throws InstantiationException, IllegalAccessException {
+        int count = basket.getConsumerCount();
+        for (int i = 0; i < count; i++) {
+            Consumer<?> co = (Consumer<?>) consumer.newInstance();
+            co.setBasket(basket);
+            co.setTraceId(ThreadContext.get("TRACE_ID"));
+            co.start();
+        }
+
+    }
+
+    /**
+     * 出异常后修改标识
+     * 
+     */
+    private void endConsumerAsError() {
+        basket.setExcuteError(true);
+    }
+
+    /**
+     * 正常结束消费者
+     * 
+     * @throws InterruptedException
+     */
+    private void endConsumer() throws InterruptedException {
+        int count = basket.getConsumerCount();
+        EndObject eo = new EndObject();
+        for (int i = 0; i < count; i++) {
+            basket.offer(eo);
+        }
+
+    }
+
+    /**
+     * 生产数据
+     * 
+     * @param ob
+     * @throws InterruptedException
+     */
+    protected void offer(Object ob) throws InterruptedException {
+        synchronized (basket) {
+            basket.offer(ob);
+        }
+    }
+
+    /**
+     * 等待所有消费者结束
+     * 
+     * @throws InterruptedException
+     */
+    private void await() throws InterruptedException {
+        basket.await();
+    }
+
+    protected abstract Object produce(Map<String, Object> param) throws Exception;
+
+}

+ 19 - 0
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/consumer/MarkWorkCreateRangeConsumer.java

@@ -0,0 +1,19 @@
+package cn.com.qmth.examcloud.task.service.consumer;
+
+import cn.com.qmth.examcloud.marking.api.MarkTaskCloudService;
+import cn.com.qmth.examcloud.marking.api.bean.MarkRangeBean;
+import cn.com.qmth.examcloud.marking.api.request.CreateMarkRangeReq;
+import cn.com.qmth.examcloud.task.base.multithread.Consumer;
+import cn.com.qmth.examcloud.web.support.SpringContextHolder;
+
+public class MarkWorkCreateRangeConsumer extends Consumer<MarkRangeBean> {
+
+    private MarkTaskCloudService markTaskCloudService = SpringContextHolder.getBean(MarkTaskCloudService.class);
+
+    @Override
+    public void consume(MarkRangeBean dto) {
+        CreateMarkRangeReq req = new CreateMarkRangeReq();
+        req.setBean(dto);
+        markTaskCloudService.createMarkRange(req);
+    }
+}

+ 35 - 3
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/job/MarkWorkPaperCreateTask.java

@@ -1,13 +1,19 @@
 package cn.com.qmth.examcloud.task.service.job;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.core.oe.admin.api.bean.ExamRecordForMarkingBean;
 import cn.com.qmth.examcloud.marking.api.MarkWorkCloudService;
+import cn.com.qmth.examcloud.marking.api.bean.MarkRangeBean;
 import cn.com.qmth.examcloud.marking.api.bean.MarkWorkBean;
 import cn.com.qmth.examcloud.marking.api.bean.MarkWorkExamBean;
 import cn.com.qmth.examcloud.marking.api.bean.MarkWorkMainBean;
@@ -20,8 +26,10 @@ import cn.com.qmth.examcloud.support.cache.bean.ExamSettingsCacheBean;
 import cn.com.qmth.examcloud.support.helper.ExamCacheTransferHelper;
 import cn.com.qmth.examcloud.task.service.consumer.MarkWorkCreateConsumer;
 import cn.com.qmth.examcloud.task.service.consumer.MarkWorkCreateItemsConsumer;
+import cn.com.qmth.examcloud.task.service.consumer.MarkWorkCreateRangeConsumer;
 import cn.com.qmth.examcloud.task.service.producer.MarkWorkCreateItemsProducer;
 import cn.com.qmth.examcloud.task.service.producer.MarkWorkCreateProducer;
+import cn.com.qmth.examcloud.task.service.producer.MarkWorkCreateRangeProducer;
 import cn.com.qmth.examcloud.web.task.AbstractTask;
 import cn.com.qmth.examcloud.web.task.ScheduleJob;
 import cn.com.qmth.examcloud.web.task.TaskTracker;
@@ -70,8 +78,9 @@ public class MarkWorkPaperCreateTask extends AbstractTask {
                         if (eb.getEndTime().getTime() <= System.currentTimeMillis()) {
                             dataEnd = true;
                         }
-                        createMarkItems(examId, bean.getId());
+                        List<ExamRecordForMarkingBean> markRangeData = createMarkItems(examId, bean.getId());
                         createStudentPapers(examId, bean.getId());
+                        createMarkRange(markRangeData);
                         if (dataEnd) {
                             markWorkExamDataEnd(bean.getId(), examId);
                         }
@@ -95,12 +104,14 @@ public class MarkWorkPaperCreateTask extends AbstractTask {
         markWorkCloudService.updateMarkWorkExamDataEnd(req);
     }
 
-    private void createMarkItems(Long examId, Long workId) throws InstantiationException, IllegalAccessException {
+    @SuppressWarnings("unchecked")
+    private List<ExamRecordForMarkingBean> createMarkItems(Long examId, Long workId)
+            throws InstantiationException, IllegalAccessException {
         MarkWorkCreateItemsProducer producer = new MarkWorkCreateItemsProducer();
         Map<String, Object> param = new HashMap<String, Object>();
         param.put("examId", examId);
         param.put("workId", workId);
-        producer.startDispose(MarkWorkCreateItemsConsumer.class, 10, param);
+        return (List<ExamRecordForMarkingBean>) producer.startDispose(MarkWorkCreateItemsConsumer.class, 10, param);
     }
 
     private void createStudentPapers(Long examId, Long workId) throws InstantiationException, IllegalAccessException {
@@ -111,6 +122,27 @@ public class MarkWorkPaperCreateTask extends AbstractTask {
         producer.startDispose(MarkWorkCreateConsumer.class, 10, param);
     }
 
+    private void createMarkRange(List<ExamRecordForMarkingBean> beans)
+            throws InstantiationException, IllegalAccessException {
+        List<MarkRangeBean> data = new ArrayList<>();
+        Set<String> set = new HashSet<>();
+        for (ExamRecordForMarkingBean bean : beans) {
+            if (!set.contains(bean.getBasePaperId())) {
+                set.add(bean.getBasePaperId());
+                MarkRangeBean mb = new MarkRangeBean();
+                mb.setBasePaperId(bean.getBasePaperId());
+                mb.setCourseId(bean.getCourseId());
+                mb.setRandomPaper(bean.getRandomPaper());
+                data.add(mb);
+            }
+        }
+
+        MarkWorkCreateRangeProducer producer = new MarkWorkCreateRangeProducer();
+        Map<String, Object> param = new HashMap<String, Object>();
+        param.put("data", data);
+        producer.startDispose(MarkWorkCreateRangeConsumer.class, 10, param);
+    }
+
     @Override
     public TaskTracker getTaskTracker() {
         return TaskTracker;

+ 40 - 25
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/producer/MarkWorkCreateItemsProducer.java

@@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory;
 
 import cn.com.qmth.examcloud.api.commons.enums.CallType;
 import cn.com.qmth.examcloud.api.commons.enums.ExamType;
+import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.core.oe.admin.api.ExamRecordForMarkingCloudService;
 import cn.com.qmth.examcloud.core.oe.admin.api.bean.ExamRecordForMarkingBean;
 import cn.com.qmth.examcloud.core.oe.admin.api.request.FindExamRecordForMarkingInfoReq;
@@ -31,11 +32,11 @@ import cn.com.qmth.examcloud.support.cache.bean.SysPropertyCacheBean;
 import cn.com.qmth.examcloud.support.enums.ExamProperties;
 import cn.com.qmth.examcloud.support.enums.MarkingType;
 import cn.com.qmth.examcloud.support.enums.MarkingWorkType;
-import cn.com.qmth.examcloud.task.base.multithread.Producer;
+import cn.com.qmth.examcloud.task.base.multithread.ResultProducer;
 import cn.com.qmth.examcloud.task.service.dto.MarkWorkCreateItemsDto;
 import cn.com.qmth.examcloud.web.support.SpringContextHolder;
 
-public class MarkWorkCreateItemsProducer extends Producer {
+public class MarkWorkCreateItemsProducer extends ResultProducer {
 
     private ExamRecordForMarkingCloudService examRecordForMarkingCloudService = SpringContextHolder
             .getBean(ExamRecordForMarkingCloudService.class);
@@ -48,7 +49,7 @@ public class MarkWorkCreateItemsProducer extends Producer {
     private static final Logger LOG = LoggerFactory.getLogger(MarkWorkCreateItemsProducer.class);
 
     @Override
-    protected void produce(Map<String, Object> param) throws Exception {
+    protected List<ExamRecordForMarkingBean> produce(Map<String, Object> param) throws Exception {
         Long examId = (Long) param.get("examId");
         Long workId = (Long) param.get("workId");
         Long batchSize = 50L;
@@ -61,10 +62,11 @@ public class MarkWorkCreateItemsProducer extends Producer {
         getExamReq.setId(examId);
         GetExamResp getExamResp = examCloudService.getExam(getExamReq);
         ExamBean examBean = getExamResp.getExamBean();
-
+        List<ExamRecordForMarkingBean> examRecordForMarkingBeanList = null;
         if (ExamType.ONLINE.name().equals(examBean.getExamType()) && checkIsAnyTimeMark(examId)) {
             // 在线考试且是随考随阅的,从调卷规则和考试记录合并拉取所有试卷。因为调卷规则随时会修改
-            List<String> result = getAllBasePaperIdsForAnyTimeMark(workId, examId);
+            examRecordForMarkingBeanList = getAllBasePaperForAnyTimeMark(workId, examId);
+            List<String> result = exludeRandomPaper(examRecordForMarkingBeanList);
             if (CollectionUtils.isNotEmpty(result)) {
                 LOG.info("创建评卷工作评分项,试卷套数:" + result.size());
                 subListDispose(result, workId, batchSize);
@@ -72,25 +74,25 @@ public class MarkWorkCreateItemsProducer extends Producer {
                 LOG.info("创建评卷工作评分项,试卷套数:0");
             }
         } else {
-            FindExamRecordForMarkingInfoReq markingReq = new FindExamRecordForMarkingInfoReq();
-            markingReq.setExamId(examId);
-            markingReq.setBatchNum(workId + "");
-            FindExamRecordForMarkingInfoResp markingResp = examRecordForMarkingCloudService
-                    .findExamRecordForMarkingInfo(markingReq);
-            List<ExamRecordForMarkingBean> examRecordForMarkingBeanList = markingResp.getExamRecordForMarkingBeanList();
+            // 从阅卷数据取
+            examRecordForMarkingBeanList = getAllBasePaperFromMarkingData(workId, examId);
             if (examRecordForMarkingBeanList != null && examRecordForMarkingBeanList.size() > 0) {
-                List<String> result = duplicateRemoval(examRecordForMarkingBeanList);
+                List<String> result = exludeRandomPaper(examRecordForMarkingBeanList);
                 LOG.info("创建评卷工作评分项,试卷套数:" + result.size());
                 subListDispose(result, workId, batchSize);
             } else {
                 LOG.info("创建评卷工作评分项,试卷套数:0");
             }
         }
-
+        if (CollectionUtils.isEmpty(examRecordForMarkingBeanList)) {
+            throw new StatusException("既没有调卷规则信息也没有考试记录信息");
+        }
+        return examRecordForMarkingBeanList;
     }
 
-    private List<String> getAllBasePaperIdsForAnyTimeMark(Long workId, Long examId) {
-        Set<String> basePaperIds = new HashSet<>();
+    private List<ExamRecordForMarkingBean> getAllBasePaperForAnyTimeMark(Long workId, Long examId) {
+        // 从调卷规则取
+        List<ExamRecordForMarkingBean> ret = new ArrayList<>();
         GetExtractConfigBeanReq req = new GetExtractConfigBeanReq();
         req.setExamId(examId);
         GetExtractConfigBeanResp res = extractConfigCloudService.getExtractConfigBean(req);
@@ -99,29 +101,42 @@ public class MarkWorkCreateItemsProducer extends Producer {
                 boolean randomPaper = CallType.RANDOM_PAPER.equals(ec.getCallType());
                 if (!randomPaper) {
                     for (ExtractConfigDetailBean ecb : ec.getDetails()) {
-                        basePaperIds.add(ecb.getPaperId());
+                        ExamRecordForMarkingBean bean = new ExamRecordForMarkingBean();
+                        bean.setBasePaperId(ecb.getPaperId());
+                        bean.setCourseId(ec.getCourseId());
+                        bean.setRandomPaper(true);
                     }
+                } else {
+                    ExamRecordForMarkingBean bean = new ExamRecordForMarkingBean();
+                    bean.setBasePaperId(ec.getRandomPaperId());
+                    bean.setCourseId(ec.getCourseId());
+                    bean.setRandomPaper(true);
                 }
             }
         }
+        // 从阅卷数据取
+        ret.addAll(getAllBasePaperFromMarkingData(workId, examId));
+        return ret;
+    }
+
+    private List<ExamRecordForMarkingBean> getAllBasePaperFromMarkingData(Long workId, Long examId) {
         FindExamRecordForMarkingInfoReq markingReq = new FindExamRecordForMarkingInfoReq();
         markingReq.setExamId(examId);
         markingReq.setBatchNum(workId + "");
+        // 包含千卷
+        markingReq.setIncludeRandomPaper(true);
         FindExamRecordForMarkingInfoResp markingResp = examRecordForMarkingCloudService
                 .findExamRecordForMarkingInfo(markingReq);
-        List<ExamRecordForMarkingBean> examRecordForMarkingBeanList = markingResp.getExamRecordForMarkingBeanList();
-        if (examRecordForMarkingBeanList != null && examRecordForMarkingBeanList.size() > 0) {
-            for (ExamRecordForMarkingBean bean : examRecordForMarkingBeanList) {
-                basePaperIds.add(bean.getBasePaperId());
-            }
-        }
-        return new ArrayList<>(basePaperIds);
+        return markingResp.getExamRecordForMarkingBeanList();
     }
 
-    private List<String> duplicateRemoval(List<ExamRecordForMarkingBean> list) {
+    private List<String> exludeRandomPaper(List<ExamRecordForMarkingBean> list) {
         Set<String> set = new HashSet<String>();
         for (ExamRecordForMarkingBean bean : list) {
-            set.add(bean.getBasePaperId());
+
+            if (bean.getRandomPaper() == null || !bean.getRandomPaper()) {
+                set.add(bean.getBasePaperId());
+            }
         }
         List<String> result = new ArrayList<>(set);
         return result;

+ 20 - 0
examcloud-task-service/src/main/java/cn/com/qmth/examcloud/task/service/producer/MarkWorkCreateRangeProducer.java

@@ -0,0 +1,20 @@
+package cn.com.qmth.examcloud.task.service.producer;
+
+import java.util.List;
+import java.util.Map;
+
+import cn.com.qmth.examcloud.marking.api.bean.MarkRangeBean;
+import cn.com.qmth.examcloud.task.base.multithread.Producer;
+
+public class MarkWorkCreateRangeProducer extends Producer {
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected void produce(Map<String, Object> param) throws Exception {
+        List<MarkRangeBean> data = (List<MarkRangeBean>) param.get("data");
+        for (MarkRangeBean bean : data) {
+            offer(bean);
+        }
+    }
+
+}