|
@@ -0,0 +1,299 @@
|
|
|
+package com.qmth.distributed.print.business.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
|
|
+import com.qmth.boot.tools.signature.SignatureType;
|
|
|
+import com.qmth.distributed.print.business.config.DictionaryConfig;
|
|
|
+import com.qmth.distributed.print.business.entity.BasicSchool;
|
|
|
+import com.qmth.distributed.print.business.entity.ExamPrintPlan;
|
|
|
+import com.qmth.distributed.print.business.entity.ExamStudent;
|
|
|
+import com.qmth.distributed.print.business.entity.TBSyncTask;
|
|
|
+import com.qmth.distributed.print.business.enums.PrintPlanStatusEnum;
|
|
|
+import com.qmth.distributed.print.business.enums.TaskResultEnum;
|
|
|
+import com.qmth.distributed.print.business.enums.TaskStatusEnum;
|
|
|
+import com.qmth.distributed.print.business.service.*;
|
|
|
+import com.qmth.distributed.print.business.util.HttpKit;
|
|
|
+import com.qmth.distributed.print.common.SignatureEntityTest;
|
|
|
+import com.qmth.distributed.print.common.contant.SystemConstant;
|
|
|
+import com.qmth.distributed.print.common.enums.ExceptionResultEnum;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.ExecutorService;
|
|
|
+import java.util.concurrent.Executors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @Date: 2021/5/20.
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class DataSyncServiceImpl implements DataSyncService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExamPrintPlanService examPrintPlanService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TBSyncTaskService tbSyncTaskService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DictionaryConfig dictionaryConfig;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private CacheService cacheService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ExamStudentService examStudentService;
|
|
|
+
|
|
|
+ private ExecutorService executors = Executors.newFixedThreadPool(5);
|
|
|
+
|
|
|
+ private static final String SAVE_EXAM_TYPE = "MULTI_MEDIA";
|
|
|
+ private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
|
|
+ private static final String POST_METHOD = "POST";
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void syncToCloudReview() {
|
|
|
+ // 查询可同步计划(同步状态为空:未同步,false:同步失败)
|
|
|
+ QueryWrapper<ExamPrintPlan> queryWrapper = new QueryWrapper<>();
|
|
|
+ queryWrapper.lambda().eq(ExamPrintPlan::getStatus, PrintPlanStatusEnum.END)
|
|
|
+ .and(q -> q.isNull(ExamPrintPlan::getSyncStatus).or().eq(ExamPrintPlan::getSyncStatus, false));
|
|
|
+ List<ExamPrintPlan> examPrintPlans = examPrintPlanService.list(queryWrapper);
|
|
|
+ if (!CollectionUtils.isEmpty(examPrintPlans)) {
|
|
|
+ for (ExamPrintPlan examPrintPlan : examPrintPlans) {
|
|
|
+ executors.execute(syncData(examPrintPlan));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private TimerTask syncData(ExamPrintPlan examPrintPlan) {
|
|
|
+ return new TimerTask() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ TBSyncTask syncTask = tbSyncTaskService.saveTask(examPrintPlan);
|
|
|
+ doSyncCore(examPrintPlan, syncTask);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 同步核心方法
|
|
|
+ *
|
|
|
+ * @param syncTask
|
|
|
+ */
|
|
|
+ @Transactional
|
|
|
+ public void doSyncCore(ExamPrintPlan examPrintPlan, TBSyncTask syncTask) {
|
|
|
+ try {
|
|
|
+ // 校验同步url
|
|
|
+ validatUrl();
|
|
|
+ // 同步计划 -> 对应云阅卷考试
|
|
|
+ Long thirdRelateId = saveExam(examPrintPlan);
|
|
|
+ // 考试同步成功,才能同步考生和题卡
|
|
|
+ if (Objects.nonNull(thirdRelateId)) {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ syncTask.setStatus(TaskStatusEnum.FINISH);
|
|
|
+ syncTask.setResult(TaskResultEnum.ERROR);
|
|
|
+ syncTask.setErrorMessage(e.getMessage());
|
|
|
+ } finally {
|
|
|
+ tbSyncTaskService.saveOrUpdate(syncTask);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验url是否非空
|
|
|
+ */
|
|
|
+ private void validatUrl() {
|
|
|
+ String hostUrl = dictionaryConfig.syncDataDomain().getHostUrl();
|
|
|
+ String examSaveUrl = dictionaryConfig.syncDataDomain().getExamSaveUrl();
|
|
|
+ String studentSaveUrl = dictionaryConfig.syncDataDomain().getStudentSaveUrl();
|
|
|
+ String cardUploadUrl = dictionaryConfig.syncDataDomain().getCardUploadUrl();
|
|
|
+
|
|
|
+ if (StringUtils.isAnyBlank(hostUrl, examSaveUrl, studentSaveUrl, cardUploadUrl)) {
|
|
|
+ throw ExceptionResultEnum.ERROR.exception("云阅卷同步接口URL未正确配置");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建考试
|
|
|
+ *
|
|
|
+ * @param examPrintPlan
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public Long saveExam(ExamPrintPlan examPrintPlan) {
|
|
|
+ String hostUrl = dictionaryConfig.syncDataDomain().getHostUrl();
|
|
|
+ String examSaveUrl = dictionaryConfig.syncDataDomain().getExamSaveUrl();
|
|
|
+ String postUrl = hostUrl.concat(examSaveUrl);
|
|
|
+ try {
|
|
|
+ //参数
|
|
|
+ Map<String, String> map = new HashMap<>();
|
|
|
+ map.put("code", String.valueOf(examPrintPlan.getId()));
|
|
|
+ map.put("name", examPrintPlan.getName());
|
|
|
+ map.put("examTime", DateUtil.format(new Date(examPrintPlan.getExamEndTime()), DATE_FORMAT));
|
|
|
+ map.put("type", SAVE_EXAM_TYPE);
|
|
|
+
|
|
|
+ String result = HttpKit.sendPost(postUrl, getHeaders(examPrintPlan.getSchoolId(), examSaveUrl), map, null, null, null);
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(result);
|
|
|
+ if (jsonObject.containsKey("id")) {
|
|
|
+ Long id = Long.valueOf(jsonObject.get("id").toString());
|
|
|
+ UpdateWrapper<ExamPrintPlan> updateWrapper = new UpdateWrapper<>();
|
|
|
+ updateWrapper.lambda().set(ExamPrintPlan::getThirdRelateId, id).set(ExamPrintPlan::getSyncStatus, true);
|
|
|
+ examPrintPlanService.update(updateWrapper);
|
|
|
+ return id;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw ExceptionResultEnum.ERROR.exception(e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 新增考生
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public void saveStudent(ExamPrintPlan examPrintPlan) {
|
|
|
+ String hostUrl = dictionaryConfig.syncDataDomain().getHostUrl();
|
|
|
+ String studentSaveUrl = dictionaryConfig.syncDataDomain().getStudentSaveUrl();
|
|
|
+ String postUrl = hostUrl.concat(studentSaveUrl);
|
|
|
+
|
|
|
+ List<ExamStudent> examStudents = examStudentService.listStudentByPrintPlanIdAndSyncStatus(examPrintPlan.getId());
|
|
|
+ for (ExamStudent examStudent : examStudents) {
|
|
|
+ Map<String, Object> resultMap = new HashMap<>();
|
|
|
+ try {
|
|
|
+ //参数
|
|
|
+ Map<String, String> map = new HashMap<>();
|
|
|
+ map.put("examId", String.valueOf(examPrintPlan.getThirdRelateId()));
|
|
|
+ map.put("examNumber", examStudent.getTicketNumber());
|
|
|
+ map.put("studentCode", examStudent.getStudentCode());
|
|
|
+ map.put("name", examStudent.getStudentName());
|
|
|
+ map.put("college", "无");
|
|
|
+// map.put("className", examStudent.get());
|
|
|
+ map.put("teacher", "无");
|
|
|
+// map.put("subjectCode", examStudent.get());
|
|
|
+// map.put("subjectName", tcPExamStudent.getCourseName());
|
|
|
+
|
|
|
+ String result = HttpKit.sendPost(postUrl, getHeaders(examPrintPlan.getSchoolId(), studentSaveUrl), map, null, null, null);
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(result);
|
|
|
+ if (jsonObject.containsKey("updateTime")) {
|
|
|
+ UpdateWrapper<ExamStudent> updateWrapper = new UpdateWrapper<>();
|
|
|
+ updateWrapper.lambda().set(ExamStudent::getSyncStatus, true).eq(ExamStudent::getId, examStudent.getId());
|
|
|
+ examStudentService.update(updateWrapper);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw ExceptionResultEnum.ERROR.exception(e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 推送题卡
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ /*public void saveCard(ExamPrintPlan examPrintPlan) {
|
|
|
+ String hostUrl = dictionaryConfig.syncDataDomain().getHostUrl();
|
|
|
+ String studentSaveUrl = dictionaryConfig.syncDataDomain().getStudentSaveUrl();
|
|
|
+ String postUrl = hostUrl.concat(studentSaveUrl);
|
|
|
+ List<TcPCard> cards = tcPCardMapper.selectListNotSyncSuccess(tcPExam.getId());
|
|
|
+ cards.forEach(tcPCard -> {
|
|
|
+ //题卡卡内容
|
|
|
+ QueryWrapper<TcPCardDetail> tcPCardDetailQueryWrapper = new QueryWrapper<>();
|
|
|
+ tcPCardDetailQueryWrapper.lambda().eq(TcPCardDetail::getCardId, tcPCard.getId());
|
|
|
+ TcPCardDetail tcPCardDetail = tcPCardDetailMapper.selectOne(tcPCardDetailQueryWrapper);
|
|
|
+
|
|
|
+ Map<String, Object> resultMap = new HashMap<>();
|
|
|
+ if (StringUtils.isNotEmpty(tcPCardDetail.getContent())) {
|
|
|
+ //生成json文件
|
|
|
+ File file = null;
|
|
|
+ try {
|
|
|
+ String filePath = makeDirs();
|
|
|
+ file = FileHelper.createJsonFile(filePath);
|
|
|
+ createFile(file, tcPCardDetail.getContent());
|
|
|
+ Map<String, String> files = new HashMap<>();
|
|
|
+ if (file.exists()) {
|
|
|
+ files.put(tcPCard.getTitle(), file.getPath());
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("同步题卡:考试id:{},题卡id:{},开始同步", tcPExam.getId(), tcPCard.getId());
|
|
|
+ //表单数据
|
|
|
+ Map<String, String> formText = new HashMap<>();
|
|
|
+ formText.put("examId", String.valueOf(tcPExam.getExternalId()));
|
|
|
+ formText.put("subjectCode", tcPCard.getCourseCode());
|
|
|
+ formText.put("format", "json");
|
|
|
+ formText.put("md5", DigestUtils.md5Hex(new FileInputStream(file)));
|
|
|
+
|
|
|
+
|
|
|
+ log.info("同步题卡:考试id:{},题卡id:{},请求url:{}, 表单参数:{},表头参数:{},发送请求", tcPExam.getId(), tcPCard.getId(), url, JSONObject.toJSONString(formText), JSONObject.toJSONString(getHeaders(cardUrl)));
|
|
|
+ String result = HttpKit.sendPost(url, getHeaders(cardUrl), formText, files, null, null);
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(result);
|
|
|
+ if (jsonObject.containsKey("success")) {
|
|
|
+ log.info("同步题卡:考试id:{},题卡id:{},请求成功,返回数据:{}", tcPExam.getId(), tcPCard.getId(), result);
|
|
|
+ resultMap.put("success", true);
|
|
|
+ resultMap.put("msg", jsonObject.get("success"));
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ resultMap.put("success", false);
|
|
|
+ resultMap.put("msg", e.getMessage());
|
|
|
+ } finally {
|
|
|
+ if (file != null && file.exists()) {
|
|
|
+ file.delete();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ resultMap.put("success", false);
|
|
|
+ resultMap.put("msg", "题卡内容为空");
|
|
|
+ }
|
|
|
+ Boolean success = Boolean.valueOf(resultMap.get("success").toString());
|
|
|
+ String msg = resultMap.get("msg").toString();
|
|
|
+ log.info("同步题卡:考试id:{},题卡id:{},请求状态:{},返回数据:{}", tcPExam.getId(), tcPCard.getId(), success, msg);
|
|
|
+
|
|
|
+ String relaName = tcPCard.getCourseName().concat("(").concat(tcPCard.getCourseCode()).concat(")");
|
|
|
+ TcPExamSyncRecord tcPExamSyncRecord = new TcPExamSyncRecord(tcPExam.getId(), "card", tcPCard.getId(), relaName, success, msg);
|
|
|
+ saveSyncRecord(tcPExamSyncRecord, "card", cards.size());
|
|
|
+ log.info("同步题卡:考试id:{},题卡id:{},保存同步记录成功,保存参数:{}", tcPExam.getId(), tcPCard.getId(), JSONObject.toJSONString(tcPExamSyncRecord));
|
|
|
+ });
|
|
|
+ }*/
|
|
|
+
|
|
|
+ /**
|
|
|
+ * http请求头
|
|
|
+ *
|
|
|
+ * @param url
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Map<String, String> getHeaders(Long schoolId, String url) {
|
|
|
+ long time = System.currentTimeMillis();
|
|
|
+ Map<String, String> header = new HashMap<>();
|
|
|
+ header.put(SystemConstant.HEADER_AUTHORIZATION, createSign(schoolId, time, url));
|
|
|
+ header.put(SystemConstant.HEADER_TIME, String.valueOf(time));
|
|
|
+ return header;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 签名
|
|
|
+ *
|
|
|
+ * @param schoolId
|
|
|
+ * @param time
|
|
|
+ * @param url
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String createSign(Long schoolId, long time, String url) {
|
|
|
+ BasicSchool basicSchool = cacheService.schoolCache(schoolId);
|
|
|
+ if (basicSchool == null) {
|
|
|
+ throw ExceptionResultEnum.ERROR.exception("学校不存在");
|
|
|
+ } else {
|
|
|
+ if (!basicSchool.getEnable()) {
|
|
|
+ throw ExceptionResultEnum.ERROR.exception("学校已禁用");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String signature = SignatureEntityTest.build(SignatureType.SECRET, POST_METHOD, url, time, basicSchool.getAccessKey(), basicSchool.getAccessSecret());
|
|
|
+ return signature;
|
|
|
+ }
|
|
|
+}
|