|
@@ -1,62 +1,18 @@
|
|
|
package cn.com.qmth.examcloud.core.oe.student.service.impl;
|
|
|
|
|
|
-import java.text.SimpleDateFormat;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.Collections;
|
|
|
-import java.util.Comparator;
|
|
|
-import java.util.Date;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.HashSet;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Locale;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Random;
|
|
|
-import java.util.Set;
|
|
|
-import java.util.TimeZone;
|
|
|
-import java.util.concurrent.TimeUnit;
|
|
|
-import java.util.stream.Collectors;
|
|
|
-
|
|
|
-import org.apache.commons.collections.CollectionUtils;
|
|
|
-import org.apache.commons.lang.math.RandomUtils;
|
|
|
-import org.apache.commons.lang3.StringUtils;
|
|
|
-import org.apache.commons.lang3.time.DateUtils;
|
|
|
-import org.slf4j.Logger;
|
|
|
-import org.slf4j.LoggerFactory;
|
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.stereotype.Service;
|
|
|
-import org.springframework.transaction.annotation.Transactional;
|
|
|
-
|
|
|
-import com.google.common.base.Splitter;
|
|
|
-
|
|
|
import cn.com.qmth.examcloud.api.commons.enums.ExamSpecialSettingsType;
|
|
|
import cn.com.qmth.examcloud.api.commons.enums.ExamType;
|
|
|
import cn.com.qmth.examcloud.api.commons.security.bean.User;
|
|
|
+import cn.com.qmth.examcloud.api.commons.security.bean.UserType;
|
|
|
import cn.com.qmth.examcloud.commons.exception.StatusException;
|
|
|
-import cn.com.qmth.examcloud.commons.util.ByteUtil;
|
|
|
-import cn.com.qmth.examcloud.commons.util.SHA256;
|
|
|
import cn.com.qmth.examcloud.commons.util.UUID;
|
|
|
-import cn.com.qmth.examcloud.commons.util.UrlUtil;
|
|
|
-import cn.com.qmth.examcloud.commons.util.Util;
|
|
|
+import cn.com.qmth.examcloud.commons.util.*;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.base.bean.ExamQuestion;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.base.bean.ExamRecordQuestions;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.base.utils.CommonUtil;
|
|
|
import cn.com.qmth.examcloud.core.oe.student.base.utils.QuestionTypeUtil;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.CheckExamInProgressInfo;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.CheckQrCodeInfo;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.EndExamInfo;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.ExamRecordPaperStruct;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.GetUpyunSignatureReq;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.StartExamInfo;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.UploadedFileAnswerInfo;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.bean.UpyunSignatureInfo;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.service.ExamBossService;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.service.ExamControlService;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.service.ExamFaceLivenessVerifyService;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.service.ExamRecordDataService;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.service.ExamRecordPaperStructService;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.service.ExamRecordQuestionsService;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.service.ExamingSessionService;
|
|
|
-import cn.com.qmth.examcloud.core.oe.student.service.FaceBiopsyService;
|
|
|
+import cn.com.qmth.examcloud.core.oe.student.bean.*;
|
|
|
+import cn.com.qmth.examcloud.core.oe.student.service.*;
|
|
|
import cn.com.qmth.examcloud.core.oe.task.api.ExamCaptureCloudService;
|
|
|
import cn.com.qmth.examcloud.core.oe.task.api.request.SaveExamCaptureSyncCompareResultReq;
|
|
|
import cn.com.qmth.examcloud.core.oe.task.api.request.UpdateExamCaptureQueuePriorityReq;
|
|
@@ -72,15 +28,7 @@ import cn.com.qmth.examcloud.reports.commons.bean.OnlineExamStudentReport;
|
|
|
import cn.com.qmth.examcloud.reports.commons.util.ReportsUtil;
|
|
|
import cn.com.qmth.examcloud.support.Constants;
|
|
|
import cn.com.qmth.examcloud.support.cache.CacheHelper;
|
|
|
-import cn.com.qmth.examcloud.support.cache.bean.CourseCacheBean;
|
|
|
-import cn.com.qmth.examcloud.support.cache.bean.ExamOrgSettingsCacheBean;
|
|
|
-import cn.com.qmth.examcloud.support.cache.bean.ExamPropertyCacheBean;
|
|
|
-import cn.com.qmth.examcloud.support.cache.bean.ExamSettingsCacheBean;
|
|
|
-import cn.com.qmth.examcloud.support.cache.bean.ExamStudentSettingsCacheBean;
|
|
|
-import cn.com.qmth.examcloud.support.cache.bean.ExtractConfigCacheBean;
|
|
|
-import cn.com.qmth.examcloud.support.cache.bean.ExtractConfigDetailCacheBean;
|
|
|
-import cn.com.qmth.examcloud.support.cache.bean.ExtractConfigPaperCacheBean;
|
|
|
-import cn.com.qmth.examcloud.support.cache.bean.SysPropertyCacheBean;
|
|
|
+import cn.com.qmth.examcloud.support.cache.bean.*;
|
|
|
import cn.com.qmth.examcloud.support.enums.ExamProperties;
|
|
|
import cn.com.qmth.examcloud.support.enums.ExamRecordStatus;
|
|
|
import cn.com.qmth.examcloud.support.enums.FaceBiopsyScheme;
|
|
@@ -95,9 +43,30 @@ import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
|
|
|
import cn.com.qmth.examcloud.web.exception.SequenceLockException;
|
|
|
import cn.com.qmth.examcloud.web.helpers.SequenceLockHelper;
|
|
|
import cn.com.qmth.examcloud.web.redis.RedisClient;
|
|
|
+import cn.com.qmth.examcloud.ws.api.WsCloudService;
|
|
|
+import cn.com.qmth.examcloud.ws.api.WsPath;
|
|
|
+import cn.com.qmth.examcloud.ws.api.enums.WebSocketEventType;
|
|
|
+import cn.com.qmth.examcloud.ws.api.request.SendFileAnswerMessageReq;
|
|
|
+import cn.com.qmth.examcloud.ws.api.request.SendScanQrCodeMessageReq;
|
|
|
+import cn.com.qmth.examcloud.ws.api.request.SendTextReq;
|
|
|
+import com.google.common.base.Splitter;
|
|
|
import main.java.com.upyun.Base64Coder;
|
|
|
import main.java.com.upyun.UpException;
|
|
|
import main.java.com.upyun.UpYunUtils;
|
|
|
+import org.apache.commons.collections.CollectionUtils;
|
|
|
+import org.apache.commons.lang.math.RandomUtils;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.apache.commons.lang3.time.DateUtils;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* @author chenken
|
|
@@ -127,10 +96,10 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
|
|
|
@Autowired
|
|
|
private ExamCloudService examCloudService;
|
|
|
-
|
|
|
+
|
|
|
@Autowired
|
|
|
private ExamBossService examBossService;
|
|
|
-
|
|
|
+
|
|
|
@Autowired
|
|
|
private FaceBiopsyService faceBiopsyService;
|
|
|
|
|
@@ -140,6 +109,9 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
@Autowired
|
|
|
private RedisClient redisClient;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private WsCloudService wsCloudService;
|
|
|
+
|
|
|
private static final String SEPARATOR = "/";
|
|
|
|
|
|
private static final String UNDERLINE = "_";
|
|
@@ -260,16 +232,16 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
if (log.isDebugEnabled()) {
|
|
|
log.debug("8 创建考试作答记录耗时:" + (System.currentTimeMillis() - startTime) + " ms");
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
//保存考试次数控制信息
|
|
|
- ExamBoss eb=examBossService.getExamBoss(examingSession.getExamId());
|
|
|
- if(eb==null) {
|
|
|
- eb=new ExamBoss();
|
|
|
+ ExamBoss eb = examBossService.getExamBoss(examingSession.getExamId());
|
|
|
+ if (eb == null) {
|
|
|
+ eb = new ExamBoss();
|
|
|
eb.setStartCount(0);
|
|
|
}
|
|
|
- eb.setStartCount(eb.getStartCount()+1);
|
|
|
+ eb.setStartCount(eb.getStartCount() + 1);
|
|
|
examBossService.saveExamBoss(examId, eb);
|
|
|
-
|
|
|
+
|
|
|
// 初始化考试会话
|
|
|
startTime = System.currentTimeMillis();
|
|
|
initializeExamRecordSession(examingSession, examRecordData, examBean);
|
|
@@ -387,6 +359,8 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
|
|
|
ExamingSession examSessionInfo = examingSessionService.getExamingSession(examRecordData.getStudentId());
|
|
|
String clientId;
|
|
|
+ String userId = key.substring(key.lastIndexOf("_") + 1);
|
|
|
+
|
|
|
// 未开启环境检测,才进行如下校验
|
|
|
if (!isTestDev(Long.valueOf(examRecordDataId))) {
|
|
|
// 非环境检测,clientId即examRecordDataId
|
|
@@ -401,7 +375,7 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
}
|
|
|
} else {
|
|
|
// 环境检测时,clientId即用户id
|
|
|
- clientId = key.substring(key.lastIndexOf("_") + 1);
|
|
|
+ clientId = userId;
|
|
|
}
|
|
|
|
|
|
// 校验通过
|
|
@@ -439,7 +413,8 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
res.setQuestionMainNumber(eqe.getMainNumber());
|
|
|
res.setSubNumber(getSubNumber(examRecordQuestions, Integer.valueOf(order)));
|
|
|
try {
|
|
|
- this.sendScanQrCodeToWebSocket(clientId, Long.valueOf(examRecordDataId), Integer.valueOf(order));
|
|
|
+ this.sendScanQrCodeToWebSocket(clientId, Long.valueOf(examRecordDataId), Integer.valueOf(order),
|
|
|
+ Long.valueOf(userId), examRecordData.getRootOrgId());
|
|
|
} catch (Exception e) {
|
|
|
throw new StatusException("100011", "消息通知失败", e);
|
|
|
}
|
|
@@ -458,8 +433,36 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
* @throws Exception
|
|
|
*/
|
|
|
@Override
|
|
|
- public void sendFileAnswerToWebSocket(Long examRecordDataId, Integer order, String fileUrl, String transferFileType, Long userId) throws Exception {
|
|
|
-
|
|
|
+ public void sendFileAnswerToWebSocket(Long examRecordDataId, Integer order, String fileUrl, String transferFileType,
|
|
|
+ Long userId, Long rootOrgId) throws Exception {
|
|
|
+ Map<String, Object> data = new HashMap<String, Object>();
|
|
|
+ data.put("examRecordDataId", examRecordDataId);
|
|
|
+ data.put("order", order);
|
|
|
+ data.put("fileUrl", fileUrl);
|
|
|
+ data.put("transferFileType", transferFileType);
|
|
|
+
|
|
|
+ SendFileAnswerMessageReq sendMessageReq = new SendFileAnswerMessageReq();
|
|
|
+ Long clientId;
|
|
|
+ // 如果是环境检测,则使用用户id(即学生id)作为clientId
|
|
|
+ if (isTestDev(examRecordDataId)) {
|
|
|
+ clientId = userId;
|
|
|
+ }
|
|
|
+ // 不是环境检测,仍然使用考试记录id作为clientId
|
|
|
+ else {
|
|
|
+ clientId = examRecordDataId;
|
|
|
+ }
|
|
|
+ sendMessageReq.setClientId(clientId);
|
|
|
+ sendMessageReq.setEventType(WebSocketEventType.GET_FILE_ANSWER.toString());
|
|
|
+ sendMessageReq.setIsSuccess(true);
|
|
|
+ sendMessageReq.setData(data);
|
|
|
+
|
|
|
+ SendTextReq sendTextReq = new SendTextReq();
|
|
|
+ sendTextReq.setUserType(UserType.STUDENT);
|
|
|
+ sendTextReq.setUserId(userId);
|
|
|
+ sendTextReq.setRootOrgId(rootOrgId);
|
|
|
+ sendTextReq.setPath(WsPath.FILE_ANSWER);
|
|
|
+ sendTextReq.setContent(JsonUtil.toJson(sendMessageReq));
|
|
|
+ wsCloudService.sendText(sendTextReq);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -471,8 +474,26 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
* @throws Exception
|
|
|
*/
|
|
|
@Override
|
|
|
- public void sendScanQrCodeToWebSocket(String clientId, Long examRecordDataId, Integer order) throws Exception {
|
|
|
-
|
|
|
+ public void sendScanQrCodeToWebSocket(String clientId, Long examRecordDataId, Integer order,
|
|
|
+ Long userId, Long rootOrgId) throws Exception {
|
|
|
+ Map<String, Object> data = new HashMap<String, Object>();
|
|
|
+ data.put("examRecordDataId", examRecordDataId);
|
|
|
+ data.put("order", order);
|
|
|
+ data.put("scanStatus", "SCANNED");
|
|
|
+ SendScanQrCodeMessageReq sendScanQrCodeMessageReq = new SendScanQrCodeMessageReq();
|
|
|
+ sendScanQrCodeMessageReq.setExamRecordDataId(examRecordDataId);
|
|
|
+ sendScanQrCodeMessageReq.setEventType(WebSocketEventType.SCAN_QR_CODE.toString());
|
|
|
+ sendScanQrCodeMessageReq.setIsSuccess(true);
|
|
|
+ sendScanQrCodeMessageReq.setClientId(clientId);
|
|
|
+ sendScanQrCodeMessageReq.setData(data);
|
|
|
+
|
|
|
+ SendTextReq sendTextReq = new SendTextReq();
|
|
|
+ sendTextReq.setUserType(UserType.STUDENT);
|
|
|
+ sendTextReq.setUserId(userId);
|
|
|
+ sendTextReq.setRootOrgId(rootOrgId);
|
|
|
+ sendTextReq.setPath(WsPath.FILE_ANSWER);
|
|
|
+ sendTextReq.setContent(JsonUtil.toJson(sendScanQrCodeMessageReq));
|
|
|
+ wsCloudService.sendText(sendTextReq);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -500,9 +521,9 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
filePath.append(".").append(req.getFileSuffix());
|
|
|
|
|
|
long expiration = expirationDate.getTime() / 1000;
|
|
|
- String bucketName=PropertyHolder.getString("$upyun.site.1.bucketName");
|
|
|
- String userName=PropertyHolder.getString("$upyun.site.1.userName");
|
|
|
- String password=PropertyHolder.getString("$upyun.site.1.password");
|
|
|
+ String bucketName = PropertyHolder.getString("$upyun.site.1.bucketName");
|
|
|
+ String userName = PropertyHolder.getString("$upyun.site.1.userName");
|
|
|
+ String password = PropertyHolder.getString("$upyun.site.1.password");
|
|
|
|
|
|
String policy = policy(bucketName, expiration, filePath.toString(), signDate, md5);
|
|
|
String sign = sign("POST", getGMTDate(signDate), bucketName, policy, userName, UpYunUtils.md5(password),
|
|
@@ -511,8 +532,8 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
u.setSignature(sign);
|
|
|
u.setFilePath(filePath.toString());
|
|
|
|
|
|
- String bucketUrl="https://v0.api.upyun.com";
|
|
|
- String upyunFileUrl=PropertyHolder.getString("$upyun.site.1.domain");
|
|
|
+ String bucketUrl = "https://v0.api.upyun.com";
|
|
|
+ String upyunFileUrl = PropertyHolder.getString("$upyun.site.1.domain");
|
|
|
u.setUploadUrl(UrlUtil.joinUrl(bucketUrl, bucketName));
|
|
|
u.setUpyunFileDomain(upyunFileUrl);
|
|
|
} catch (UpException e) {
|
|
@@ -520,6 +541,7 @@ public class ExamControlServiceImpl implements ExamControlService {
|
|
|
}
|
|
|
return u;
|
|
|
}
|
|
|
+
|
|
|
/**
|
|
|
* @param bucketName //不能为空
|
|
|
* @param expiration //不能为空
|