Przeglądaj źródła

Merge remote-tracking branch 'origin/release_v5.0.6'

# Conflicts:
#	examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/bean/AdminOperateReport.java
#	examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/bean/OnlineExamStudentReport.java
#	examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/bean/OnlineStudentReport.java
#	examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/bean/OnlineUserReport.java
#	examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/bean/OperateReport.java
#	examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/util/ReportsUtil.java
deason 1 tydzień temu
rodzic
commit
820f1e92a4

+ 6 - 16
examcloud-common-models/src/main/java/cn/com/qmth/examcloud/support/CacheConstants.java

@@ -1,9 +1,7 @@
 package cn.com.qmth.examcloud.support;
 
 /**
- * 缓存相关常量
- * 注:cache key 命名规则
- * $模块:关键字:参数1_参数2  示例:$OE:XXX:123_abc
+ * 缓存相关常量 注:cache key 命名规则 $模块:关键字:参数1_参数2 示例:$OE:XXX:123_abc
  */
 public interface CacheConstants {
 
@@ -79,6 +77,11 @@ public interface CacheConstants {
      */
     String LOCK_M_EXPORT_TASK = LOCK_PREFIX + "M_EXPORT_TASK:";
 
+    /**
+     * 阅卷任务更新锁
+     */
+    String LOCK_M_MARK_WORK_MODIFY_TASK = LOCK_PREFIX + "M_MARK_WORK_MODIFY_TASK";
+
     /**
      * 阅卷导入任务锁:{workId}
      */
@@ -94,8 +97,6 @@ public interface CacheConstants {
      */
     String LOCK_E_EXAM_SPECIAL_SETTINGS = LOCK_PREFIX + "E_EXAM_SPECIAL_SETTINGS:";
 
-
-
     /* #################### 基础模块 #################### */
 
     /**
@@ -208,8 +209,6 @@ public interface CacheConstants {
      */
     String CACHE_B_VERIFY_CODE_RESOURCE = "$B:VERIFY_CODE_RESOURCE:";
 
-
-
     /* #################### 考务模块 #################### */
 
     /**
@@ -252,8 +251,6 @@ public interface CacheConstants {
      */
     String CACHE_E_EXAM_STUDENT_PROP = "$E:EXAM_STUDENT_PROP:";
 
-
-
     /* #################### 题库模块 #################### */
 
     /**
@@ -296,8 +293,6 @@ public interface CacheConstants {
      */
     String CACHE_Q_QUESTION_ANSWER = "$Q:QUESTION_ANSWER:";
 
-
-
     /* #################### 网考模块 #################### */
 
     /**
@@ -390,8 +385,6 @@ public interface CacheConstants {
      */
     String CACHE_OE_EXPORT_TASK_STOP = "$OE:EXPORT_TASK_STOP:";
 
-
-
     /* #################### Exchange模块 #################### */
 
     /**
@@ -404,8 +397,6 @@ public interface CacheConstants {
      */
     String CACHE_EX_SMS = "$EX:SMS:";
 
-
-
     /* #################### APP模块 #################### */
 
     /**
@@ -413,5 +404,4 @@ public interface CacheConstants {
      */
     String CACHE_APP_REQ_TRACE = "$APP:REQ_TRACE:";
 
-
 }

+ 3 - 2
examcloud-common-models/src/main/java/cn/com/qmth/examcloud/support/enums/ExamProperties.java

@@ -44,7 +44,7 @@ public enum ExamProperties {
     IP_LIMIT("是否IP限制"),
     IP_TOTAL_LIMIT("IP访问设置-整体控制-白名单黑名单"),
 
-    //已废弃
+    // 已废弃
     IP_ADDRESSES("IP白名单"),
 
     IS_OBJ_SCORE_VIEW("是否显示客观题成绩"),
@@ -66,7 +66,8 @@ public enum ExamProperties {
     MAX_SWITCH_SCREEN_COUNT("控制设置-切屏次数限制"),
     SHOW_MULTIPLE_CHOICE_WARNING("是否考生作答多选题所选答案不足两个时警告提示"),
     FACE_VERIFY_FORCE_EXIT("考中活体不通过强制退出"),
-    VIRTUAL_CAMERA_AUDIT_ENABLED("虚拟摄像头进入待审");
+    VIRTUAL_CAMERA_AUDIT_ENABLED("虚拟摄像头进入待审"),
+    MARKING_WORK_TYPE("阅卷任务创建模式");
 
     ExamProperties(String desc) {
         this.desc = desc;

+ 42 - 0
examcloud-common-models/src/main/java/cn/com/qmth/examcloud/support/enums/MarkingType.java

@@ -0,0 +1,42 @@
+/*
+ * *************************************************
+ * Copyright (c) 2018 QMTH. All Rights Reserved.
+ * Created by Deason on 2018-08-31 10:50:02.
+ * *************************************************
+ */
+
+package cn.com.qmth.examcloud.support.enums;
+
+/**
+ * 阅卷类型
+ *
+ * @author: QMTH
+ * @since: 2018/8/31
+ */
+public enum MarkingType {
+	/**
+	 * 全部评阅
+	 */
+    ALL("全部评阅"),
+
+    /**
+     * 客观分最高
+     */
+    OBJECT_SCORE_MAX("客观分最高"),
+
+    /**
+     * 最后一次提交
+     */
+    LAST_SUBMIT("最后一次提交");
+
+    private String title;
+
+    MarkingType(String title) {
+        this.title = title;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+}

+ 20 - 0
examcloud-common-models/src/main/java/cn/com/qmth/examcloud/support/enums/MarkingWorkType.java

@@ -0,0 +1,20 @@
+
+package cn.com.qmth.examcloud.support.enums;
+
+public enum MarkingWorkType {
+
+    END_EXAM_MARK("考试结束之后阅卷"),
+
+    ANYTIME("随考随阅");
+
+    private String title;
+
+    MarkingWorkType(String title) {
+        this.title = title;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+}

+ 2 - 2
examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/bean/AdminOperateReport.java

@@ -19,8 +19,8 @@ public class AdminOperateReport extends BaseReport {
         this.operateUserId = operateUserId;
         this.operate = operate;
         this.operateInfo = operateInfo;
-        this.topic = ReportsUtil.getReportTopic();
-        this.tag = Tag.ADMIN_OPERATE_INFO.getCode();
+        this.topic = ReportsUtil.curTopic(Tag.ADMIN_OPERATE_INFO);
+        this.tag = Tag.ADMIN_OPERATE_INFO.name();
     }
 
     public AdminOperateReport() {

+ 2 - 2
examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/bean/OnlineExamStudentReport.java

@@ -55,8 +55,8 @@ public class OnlineExamStudentReport extends BaseReport {
         this.studentId = studentId;
         this.examId = examId;
         this.examStudentId = examStudentId;
-        this.topic = ReportsUtil.getReportTopic();
-        this.tag = Tag.ONLINE_EXAM_STUDENT.getCode();
+        this.topic = ReportsUtil.curTopic(Tag.ONLINE_EXAM_STUDENT);
+        this.tag = Tag.ONLINE_EXAM_STUDENT.name();
     }
 
 }

+ 2 - 2
examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/bean/OnlineStudentReport.java

@@ -33,8 +33,8 @@ public class OnlineStudentReport extends BaseReport {
         super();
         this.rootOrgId = rootOrgId;
         this.studentId = studentId;
-        this.topic = ReportsUtil.getReportTopic();
-        this.tag = Tag.ONLINE_STUDENT.getCode();
+        this.topic = ReportsUtil.curTopic(Tag.ONLINE_STUDENT);
+        this.tag = Tag.ONLINE_STUDENT.name();
     }
 
 }

+ 2 - 2
examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/bean/OnlineUserReport.java

@@ -33,8 +33,8 @@ public class OnlineUserReport extends BaseReport {
         super();
         this.rootOrgId = rootOrgId;
         this.userId = userId;
-        this.topic = ReportsUtil.getReportTopic();
-        this.tag = Tag.ONLINE_USER.getCode();
+        this.topic = ReportsUtil.curTopic(Tag.ONLINE_USER);
+        this.tag = Tag.ONLINE_USER.name();
     }
 
 }

+ 2 - 2
examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/bean/OperateReport.java

@@ -27,8 +27,8 @@ public class OperateReport extends BaseReport {
         this.examStudentId = examStudentId;
         this.operateUserType = operateClient;
         this.operate = operate;
-        this.topic = ReportsUtil.getReportTopic();
-        this.tag = Tag.OPERATE_INFO.getCode();
+        this.topic = ReportsUtil.curTopic(Tag.OPERATE_INFO);
+        this.tag = Tag.OPERATE_INFO.name();
     }
 
     public OperateReport() {

+ 11 - 52
examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/enums/Tag.java

@@ -3,74 +3,33 @@ package cn.com.qmth.examcloud.reports.commons.enums;
 public enum Tag {
 
     /**
-     * 学生
+     * 在线学生
      */
-    ONLINE_STUDENT("ONLINE_STUDENT", "ONLINE_STUDENT_GROUP", "学生"),
+    ONLINE_STUDENT,
 
     /**
-     * 考生
+     * 在线考生
      */
-    ONLINE_EXAM_STUDENT("ONLINE_EXAM_STUDENT", "ONLINE_EXAM_STUDENT_GROUP", "考生"),
+    ONLINE_EXAM_STUDENT,
 
     /**
-     * 后台用户
+     * 在线用户
      */
-    ONLINE_USER("ONLINE_USER", "ONLINE_USER_GROUP", "后台用户"),
+    ONLINE_USER,
 
     /**
-     * 操作日志
+     * 学生相关操作日志
      */
-    OPERATE_INFO("OPERATE_INFO", "OPERATE_INFO_GROUP", "操作日志"),
+    OPERATE_INFO,
 
     /**
      * 考试过程记录
      */
-    EXAM_PROCESS_RECORD("EXAM_PROCESS_RECORD", "EXAM_PROCESS_RECORD_GROUP", "考试过程记录"),
+    EXAM_PROCESS_RECORD,
 
     /**
-     * 后台用户操作日志
+     * 管理端-用户相关操作日志
      */
-    ADMIN_OPERATE_INFO("ADMIN_OPERATE_INFO", "ADMIN_OPERATE_INFO_GROUP", "后台用户操作日志"),
-    ;
-
-    // ===========================================================================
-
-    /**
-     * 码
-     */
-    private String code;
-
-    /**
-     * 描述
-     */
-    private String group;
-
-    /**
-     * 描述
-     */
-    private String desc;
-
-    /**
-     * 构造函数
-     *
-     * @param desc
-     */
-    private Tag(String code, String group, String desc) {
-        this.code = code;
-        this.group = group;
-        this.desc = desc;
-    }
-
-    public String getDesc() {
-        return desc;
-    }
-
-    public String getCode() {
-        return code;
-    }
-
-    public String getGroup() {
-        return group;
-    }
+    ADMIN_OPERATE_INFO;
 
 }

+ 47 - 37
examcloud-support/src/main/java/cn/com/qmth/examcloud/reports/commons/util/ReportsUtil.java

@@ -1,16 +1,14 @@
 package cn.com.qmth.examcloud.reports.commons.util;
 
-import cn.com.qmth.examcloud.commons.exception.StatusException;
 import cn.com.qmth.examcloud.commons.util.ThreadLocalUtil;
 import cn.com.qmth.examcloud.reports.commons.bean.BaseReport;
-import cn.com.qmth.examcloud.reports.commons.enums.MqType;
+import cn.com.qmth.examcloud.reports.commons.enums.Tag;
 import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
 import cn.com.qmth.examcloud.web.support.IpUtil;
 import cn.com.qmth.examcloud.web.support.ServletUtil;
 import com.alibaba.fastjson.JSON;
 import com.aliyun.openservices.ons.api.*;
 import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -25,39 +23,43 @@ public class ReportsUtil {
 
     private static final Logger LOG = LoggerFactory.getLogger(ReportsUtil.class);
 
-    private static final String KEY = "mq-report-data";
+    private static final String GROUP_PRODUCER_PREFIX = "ec_producer_";
 
-    private static Producer producer;
+    private static final String GROUP_CONSUMER_PREFIX = "ec_consumer_";
+
+    private static final String TOPIC_PREFIX = "ec_topic_";
 
-    private static String mqType = PropertyHolder.getString("$report.mq-type", "rocketmq");
+    private static final String DATA_KEY = "ec_mq_data";
+
+    private static Producer producer;
 
-    private static Boolean reportEnable = PropertyHolder.getBoolean("$report.enable", false);
+    private static Boolean reportEnable = PropertyHolder.getBoolean("examcloud.rocketmq.enable", false);
 
     static {
         if (reportEnable) {
-            if (MqType.ROCKETMQ.getCode().equals(mqType)) {
-                Properties properties = new Properties();
-                // AccessKeyId 阿里云身份验证,在阿里云服务器管理控制台创建。
-                properties.put(PropertyKeyConst.AccessKey, PropertyHolder.getString("$rocketmq-accesskey"));
-                // AccessKeySecret 阿里云身份验证,在阿里云服务器管理控制台创建。
-                properties.put(PropertyKeyConst.SecretKey, PropertyHolder.getString("$rocketmq-secretkey"));
-                // 设置发送超时时间,单位毫秒。
-                properties.setProperty(PropertyKeyConst.SendMsgTimeoutMillis, "3000");
-                // 设置 TCP 接入域名,进入控制台的实例详情页面的 TCP 协议客户端接入点区域查看。
-                properties.put(PropertyKeyConst.NAMESRV_ADDR, PropertyHolder.getString("$rocketmq-namesrv-addr"));
-
-                producer = ONSFactory.createProducer(properties);
-                // 在发送消息前,必须调用 start 方法来启动 Producer,只需调用一次即可。
-                producer.start();
-            } else {
-                LOG.error("value of property[$report.mq-type] is wrong!");
-            }
+            Properties properties = new Properties();
+            // AccessKeyId 阿里云身份验证,在阿里云服务器管理控制台创建。
+            properties.put(PropertyKeyConst.AccessKey, PropertyHolder.getString("examcloud.rocketmq.accesskey"));
+            // AccessKeySecret 阿里云身份验证,在阿里云服务器管理控制台创建。
+            properties.put(PropertyKeyConst.SecretKey, PropertyHolder.getString("examcloud.rocketmq.secretkey"));
+            // 设置发送超时时间,单位毫秒。
+            properties.setProperty(PropertyKeyConst.SendMsgTimeoutMillis, "3000");
+            // 设置 TCP 接入域名,进入控制台的实例详情页面的 TCP 协议客户端接入点区域查看。
+            properties.put(PropertyKeyConst.NAMESRV_ADDR, PropertyHolder.getString("examcloud.rocketmq.namesrv_addr"));
+
+            // 生产组名称
+            properties.put(PropertyKeyConst.GROUP_ID, curProducerGroup());
+
+            producer = ONSFactory.createProducer(properties);
+            // 在发送消息前,必须调用 start 方法来启动 Producer,只需调用一次即可。
+            producer.start();
+            LOG.warn("Rocketmq Producer started...");
         }
     }
 
     private static void sendReportRocket(Boolean onException) {
         @SuppressWarnings("unchecked")
-        List<BaseReport> list = (List<BaseReport>) ThreadLocalUtil.get(KEY);
+        List<BaseReport> list = (List<BaseReport>) ThreadLocalUtil.get(DATA_KEY);
         if (CollectionUtils.isNotEmpty(list)) {
             for (BaseReport b : list) {
                 if (!onException || (onException && b.getReportOnException())) {
@@ -82,7 +84,7 @@ public class ReportsUtil {
                     }
                 }
             }
-            ThreadLocalUtil.set(KEY, null);
+            ThreadLocalUtil.set(DATA_KEY, null);
         }
     }
 
@@ -93,10 +95,10 @@ public class ReportsUtil {
             }
             setReportCommonData(report);
             @SuppressWarnings("unchecked")
-            List<BaseReport> list = (List<BaseReport>) ThreadLocalUtil.get(KEY);
+            List<BaseReport> list = (List<BaseReport>) ThreadLocalUtil.get(DATA_KEY);
             if (list == null) {
                 list = new ArrayList<BaseReport>();
-                ThreadLocalUtil.set(KEY, list);
+                ThreadLocalUtil.set(DATA_KEY, list);
             }
             list.add(report);
         } catch (Exception e) {
@@ -105,9 +107,7 @@ public class ReportsUtil {
     }
 
     public static void sendReport(Boolean onException) {
-        if (MqType.ROCKETMQ.getCode().equals(mqType)) {
-            sendReportRocket(onException);
-        }
+        sendReportRocket(onException);
     }
 
     private static void setReportCommonData(BaseReport report) {
@@ -118,16 +118,26 @@ public class ReportsUtil {
         } catch (Exception e) {
             LOG.debug("获取本机IP出错", e);
         }
+
         report.setReportHost(ip);
         report.setRemoteHost(IpUtil.getRemoteIp(ServletUtil.getRequest()));
         report.setReportTime(new Date());
     }
 
-    public static String getReportTopic() {
-        String topic = PropertyHolder.getString("$report.mq-topic");
-        if (StringUtils.isBlank(topic)) {
-            throw new StatusException("$report.mq-topic 未配置");
-        }
-        return topic;
+    public static String curTopic(Tag tag) {
+        return TOPIC_PREFIX + tag.name().toLowerCase() + "_" + curProfile();
     }
+
+    public static String curConsumerGroup(Tag tag) {
+        return GROUP_CONSUMER_PREFIX + tag.name().toLowerCase() + "_" + curProfile();
+    }
+
+    public static String curProducerGroup() {
+        return GROUP_PRODUCER_PREFIX + "_" + curProfile();
+    }
+
+    public static String curProfile() {
+        return PropertyHolder.getString("spring.profiles.active", "");
+    }
+
 }

+ 110 - 0
examcloud-support/src/main/java/cn/com/qmth/examcloud/support/sms/SmsHelper.java

@@ -0,0 +1,110 @@
+package cn.com.qmth.examcloud.support.sms;
+
+import cn.com.qmth.examcloud.commons.exception.StatusException;
+import cn.com.qmth.examcloud.commons.util.JsonMapper;
+import cn.com.qmth.examcloud.web.bootstrap.PropertyHolder;
+import com.aliyuncs.CommonRequest;
+import com.aliyuncs.CommonResponse;
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.IAcsClient;
+import com.aliyuncs.http.MethodType;
+import com.aliyuncs.http.ProtocolType;
+import com.aliyuncs.profile.DefaultProfile;
+import com.fasterxml.jackson.databind.JsonNode;
+import org.apache.tomcat.util.buf.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class SmsHelper {
+
+    private static final Logger log = LoggerFactory.getLogger(SmsHelper.class);
+
+    /**
+     * 短信配置代码 - 验证码
+     */
+    public static final String SMS_YZM = "YZM";
+
+    /**
+     * 短信配置代码 - 人脸比对失败报警短信
+     */
+    public static final String SMS_FACECOMPARE = "FACECOMPARE";
+
+    /**
+     * 短信配置代码 - 百度活体检测处理失败报警短信
+     */
+    public static final String SMS_FACELIVENESS = "FACELIVENESS";
+
+    /**
+     * 发短信
+     *
+     * @param signName       短信签名
+     * @param templateCode   短信模板
+     * @param phoneList      手机号码
+     * @param templateParams 短信模板参数
+     * @author WANGWEI
+     */
+    public static void send(String signName, String templateCode, List<String> phoneList,
+                            Map<String, String> templateParams) {
+        String accessKeyId = PropertyHolder.getString("aliyun.sms.accessKeyId");
+        String accessSecret = PropertyHolder.getString("aliyun.sms.accessKeySecret");
+
+        DefaultProfile profile = DefaultProfile.getProfile("default", accessKeyId, accessSecret);
+        IAcsClient client = new DefaultAcsClient(profile);
+
+        CommonRequest request = new CommonRequest();
+        request.setProtocol(ProtocolType.HTTPS);
+        request.setMethod(MethodType.POST);
+        request.setDomain("dysmsapi.aliyuncs.com");
+        request.setVersion("2017-05-25");
+        request.setAction("SendSms");
+
+        String phoneNumbers = StringUtils.join(phoneList, ',');
+        String params = new JsonMapper().toJson(templateParams);
+        request.putQueryParameter("SignName", signName);
+        request.putQueryParameter("TemplateCode", templateCode);
+        request.putQueryParameter("TemplateParam", params);
+        request.putQueryParameter("PhoneNumbers", phoneNumbers);
+
+        try {
+            CommonResponse response = client.getCommonResponse(request);
+            String responseData = response.getData();
+
+            // 成功示例:{"Message":"OK","Code":"OK","RequestId":"xxx","BizId":"xxx"}
+            String code = null;
+            JsonNode jsonNode = new JsonMapper().getNode(responseData);
+            if (jsonNode != null) {
+                JsonNode codeNode = jsonNode.get("Code");
+                code = codeNode != null ? codeNode.asText() : null;
+            }
+
+            if (!"OK".equals(code)) {
+                log.error("sms send fail:{}", responseData);
+                throw new StatusException("101001", "短信发送失败");
+            }
+            log.warn("短信发送成功!phoneNumbers:{} params:{}", phoneNumbers, params);
+        } catch (StatusException e) {
+            throw e;
+        } catch (Exception e) {
+            log.error("sms send error:{}", e.getMessage());
+            throw new StatusException("101002", "短信发送异常", e);
+        }
+    }
+
+    public static void main(String[] args) {
+        List<String> phones = Arrays.asList("18600000001");
+
+        Map<String, String> templateParams = new HashMap<>();
+        // templateParams.put("code", "123");
+        // SmsHelper.send("考试云平台", "SMS_153725618", phones, templateParams);
+
+        templateParams.put("name", "api");
+        templateParams.put("time", new SimpleDateFormat("HH:mm:ss").format(new Date()));
+        templateParams.put("status", "500");
+        templateParams.put("msg", "接口异常");
+        SmsHelper.send("启明泰和", "SMS_246635756", phones, templateParams);
+    }
+
+}