1
0
ting.yin 4 rokov pred
rodič
commit
c66d05f7ae

+ 16 - 5
stmms-biz/src/main/java/cn/com/qmth/stmms/biz/exam/model/DataSync.java

@@ -5,11 +5,15 @@ import java.util.Date;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
 import javax.persistence.Id;
 import javax.persistence.Table;
 import javax.persistence.Temporal;
 import javax.persistence.TemporalType;
 
+import cn.com.qmth.stmms.common.enums.ExamSource;
+
 @Entity
 @Table(name = "eb_data_sync")
 public class DataSync implements Serializable {
@@ -22,6 +26,13 @@ public class DataSync implements Serializable {
     @Column(name = "school_id")
     private Integer schoolId;
 
+    /**
+     * 来源
+     */
+    @Column(name = "source", length = 16, nullable = false)
+    @Enumerated(EnumType.STRING)
+    private ExamSource source;
+
     @Temporal(TemporalType.TIMESTAMP)
     @Column(name = "create_time")
     private Date createTime;
@@ -30,7 +41,7 @@ public class DataSync implements Serializable {
     @Column(name = "update_time")
     private Date updateTime;
 
-    @Column(name = "root_org_id", nullable = false)
+    @Column(name = "root_org_id")
     private String rootOrgId;
 
     @Column(name = "cloud_exam_id", nullable = false)
@@ -42,10 +53,7 @@ public class DataSync implements Serializable {
     @Column(name = "next_id")
     private Long nextId;
 
-    @Column(name = "student_url", nullable = false)
-    private String studentUrl;
-
-    @Column(name = "app_id", nullable = false)
+    @Column(name = "app_id")
     private String appId;
 
     @Column(name = "secret_key", nullable = false)
@@ -54,6 +62,9 @@ public class DataSync implements Serializable {
     @Column(name = "finished", nullable = false)
     private boolean finished;
 
+    @Column(name = "student_url", nullable = false)
+    private String studentUrl;
+
     @Column(name = "subject_url", nullable = false)
     private String subjectUrl;
 

+ 34 - 0
stmms-common/src/main/java/cn/com/qmth/stmms/common/enums/ExamSource.java

@@ -0,0 +1,34 @@
+package cn.com.qmth.stmms.common.enums;
+
+public enum ExamSource {
+
+    EXAM_CLOUD("云平台", 1), ONLINE_EXAM("在线考试平台", 2);
+
+    private String name;
+
+    private int value;
+
+    private ExamSource(String name, int value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getValue() {
+        return value;
+    }
+
+    public static ExamSource findByValue(int value) {
+        ExamSource status = null;
+        for (ExamSource s : ExamSource.values()) {
+            if (s.getValue() == value) {
+                status = s;
+                break;
+            }
+        }
+        return status;
+    }
+}

+ 278 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/thread/OnlineExamThread.java

@@ -0,0 +1,278 @@
+package cn.com.qmth.stmms.admin.thread;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cn.com.qmth.stmms.admin.utils.OnlineExamHttpUtil;
+import cn.com.qmth.stmms.biz.exam.model.DataSync;
+import cn.com.qmth.stmms.biz.exam.model.Exam;
+import cn.com.qmth.stmms.biz.exam.model.ExamQuestion;
+import cn.com.qmth.stmms.biz.exam.model.ExamStudent;
+import cn.com.qmth.stmms.biz.exam.model.ExamSubject;
+import cn.com.qmth.stmms.biz.exam.model.MarkGroup;
+import cn.com.qmth.stmms.biz.exam.service.DataSyncService;
+import cn.com.qmth.stmms.biz.exam.service.ExamQuestionService;
+import cn.com.qmth.stmms.biz.exam.service.ExamService;
+import cn.com.qmth.stmms.biz.exam.service.ExamStudentService;
+import cn.com.qmth.stmms.biz.exam.service.ExamSubjectService;
+import cn.com.qmth.stmms.biz.exam.service.MarkGroupService;
+import cn.com.qmth.stmms.biz.file.enums.FormatType;
+import cn.com.qmth.stmms.biz.file.service.FileService;
+import cn.com.qmth.stmms.biz.lock.LockService;
+import cn.com.qmth.stmms.common.enums.LockType;
+import cn.com.qmth.stmms.common.enums.MarkMode;
+import cn.com.qmth.stmms.common.enums.SubjectiveStatus;
+
+import com.aliyun.oss.common.utils.BinaryUtil;
+
+public class OnlineExamThread implements Runnable {
+
+    protected static Logger log = LoggerFactory.getLogger(OnlineExamThread.class);
+
+    private DataSync dataSync;
+
+    private ExamStudentService studentService;
+
+    private ExamSubjectService subjectService;
+
+    private ExamQuestionService questionService;
+
+    private MarkGroupService groupService;
+
+    private ExamService examService;
+
+    private FileService fileService;
+
+    private LockService lockService;
+
+    private DataSyncService dataSyncService;
+
+    private Integer pageSize;
+
+    private OnlineExamHttpUtil studentHttp;
+
+    private OnlineExamHttpUtil subjectPaperHttp;
+
+    public static final String PAPER_STRUCT = "paperStructList";
+
+    public static final String ID = "id";
+
+    public static final String EXAM_ID = "examId";
+
+    public static final String PAPER_ID = "paperId";
+
+    public static final String COURSE_CODE = "courseCode";
+
+    public static final String COURSE_NAME = "courseName";
+
+    public static final String ANSWERS = "answers";
+
+    public static final String RECORDS = "records";
+
+    public static final String START_ID = "examStudentIdGt";
+
+    public static final String DEFAULT_NULL = "#";
+
+    public static final String COUNT = "count";
+
+    public OnlineExamThread(DataSync dataSync, Integer pageSize, LockService lockService,
+            DataSyncService dataSyncService, ExamService examService, ExamStudentService studentService,
+            ExamSubjectService subjectService, ExamQuestionService questionService, MarkGroupService groupService,
+            FileService fileService) {
+        this.dataSync = dataSync;
+        this.lockService = lockService;
+        this.dataSyncService = dataSyncService;
+        this.examService = examService;
+        this.studentService = studentService;
+        this.subjectService = subjectService;
+        this.questionService = questionService;
+        this.groupService = groupService;
+        this.fileService = fileService;
+        this.pageSize = pageSize;
+        this.studentHttp = new OnlineExamHttpUtil(dataSync.getSecretKey(), dataSync.getSecretKey(),
+                dataSync.getStudentUrl());
+        this.subjectPaperHttp = new OnlineExamHttpUtil(dataSync.getSecretKey(), dataSync.getSecretKey(),
+                dataSync.getSubjectPaperUrl());
+    }
+
+    @Override
+    public void run() {
+        log.info("start data sync for examId=" + dataSync.getExamId());
+        try {
+            // 获取考试信息
+            Exam exam = examService.findById(dataSync.getExamId());
+            DataSync sync = dataSyncService.findByExamId(dataSync.getExamId());
+            if (sync == null) {
+                sync = dataSync;
+                sync.setCreateTime(new Date());
+                dataSyncService.save(sync);
+            }
+            Map<String, ExamSubject> subjectMap = new HashMap<String, ExamSubject>();
+            Map<String, Object> datas = new HashMap<String, Object>();
+            datas.put(EXAM_ID, dataSync.getCloudExamId());
+
+            // 获取考生
+            Long startId = 0L;
+            if (sync.getNextId() != null) {
+                startId = sync.getNextId();
+            }
+            while (startId != null) {
+                datas.put(START_ID, startId);
+                datas.put(COUNT, pageSize);
+                String studentResult = studentHttp.httpAction(null, datas);
+                JSONArray studentArray = JSONArray.fromObject(studentResult);
+                if (studentArray.size() == 0) {
+                    startId = null;
+                }
+                for (int k = 0; k < studentArray.size(); k++) {
+                    JSONObject student = studentArray.getJSONObject(k);
+                    String subjectName = student.getString(COURSE_NAME);
+                    JSONArray recordArray = student.getJSONArray(RECORDS);
+                    List<ExamStudent> list = new ArrayList<ExamStudent>();
+                    Date now = new Date();
+                    for (int j = 0; j < recordArray.size(); j++) {
+                        JSONObject record = recordArray.getJSONObject(j);
+                        // 保存科目试卷
+                        datas.put(ID, record.getString(PAPER_ID));
+                        datas.put("filter", "subjective");
+                        String paperResult = subjectPaperHttp.httpAction(null, datas);
+                        JSONObject paperJson = JSONObject.fromObject(paperResult);
+                        String subjectCode = paperJson.getString("paperId");
+                        String paper = paperJson.getString("details");
+                        byte[] paperData = paper.getBytes(StandardCharsets.UTF_8);
+                        fileService.uploadPaper(new ByteArrayInputStream(paperData), BinaryUtil.encodeMD5(paperData),
+                                exam.getId(), subjectCode, FormatType.JSON);
+                        this.saveSubject(subjectMap, exam.getId(), subjectCode, subjectName,
+                                JSONArray.fromObject(paper));
+                        // 保存考生数据
+                        ExamStudent examStudent = getExamStudent(exam, student, subjectCode, record.getString(ID), now);
+                        list.add(examStudent);
+                        // 保存考生作答
+                        String answerJson = record.getString(ANSWERS);
+                        byte[] jsonData = answerJson.getBytes(StandardCharsets.UTF_8);
+                        fileService.uploadJson(new ByteArrayInputStream(jsonData), BinaryUtil.encodeMD5(jsonData),
+                                exam.getId(), examStudent.getSecretNumber());
+                        subjectService.updateUploadCount(exam.getId(), subjectCode,
+                                (int) studentService.countUploadedByExamIdAndSubjectCode(exam.getId(), subjectCode));
+                    }
+                    startId = student.getLong(ID);
+                }
+                sync.setUpdateTime(new Date());
+                sync.setNextId(startId);
+                dataSyncService.save(sync);
+            }
+
+            sync.setFinished(true);
+            dataSyncService.save(sync);
+        } catch (Exception e) {
+            log.error("data sync exception for examId=" + dataSync.getExamId(), e);
+        } finally {
+            lockService.unlock(LockType.DATA_SYNC, dataSync.getExamId());
+            log.info("finish data sync for examId=" + dataSync.getExamId());
+        }
+    }
+
+    private ExamStudent getExamStudent(Exam exam, JSONObject student, String paperCode, String examNumber, Date now) {
+        ExamStudent examStudent = new ExamStudent();
+        examStudent.setExamId(exam.getId());
+        examStudent.setStudentCode(student.getString("identity"));
+        examStudent.setName(student.getString("name"));
+        examStudent.setSubjectCode(paperCode);
+        examStudent.setSubjectName(student.getString(COURSE_NAME));
+        examStudent.setExamNumber(examNumber);
+        examStudent.setSecretNumber(examNumber);
+        examStudent.setCollege(DEFAULT_NULL);
+        examStudent.setClassName(DEFAULT_NULL);
+        examStudent.setTeacher(DEFAULT_NULL);
+        examStudent.setCampusName(DEFAULT_NULL);
+        examStudent.setPaperType(DEFAULT_NULL);
+        examStudent.setSchoolId(exam.getSchoolId());
+        examStudent.setAbsent(false);
+        examStudent.setUpload(true);
+        examStudent.setManualAbsent(false);
+        examStudent.setBreach(false);
+        examStudent.setException(false);
+        examStudent.setSliceCount(0);
+        examStudent.setSheetCount(0);
+        examStudent.setObjectiveScore(0d);
+        examStudent.setSubjectiveScore(0d);
+        examStudent.setSubjectiveStatus(SubjectiveStatus.UNMARK);
+        examStudent.setAnswers(null);
+        examStudent.setBatchCode(null);
+        examStudent.setUploadTime(now);
+        return examStudent;
+    }
+
+    private ExamSubject saveSubject(Map<String, ExamSubject> subjectMap, Integer examId, String subjectCode,
+            String subjectName, JSONArray questionArray) {
+        ExamSubject subject = subjectMap.get(subjectCode);
+        if (subject != null) {
+            return subject;
+        }
+        subject = subjectService.find(examId, subjectCode);
+        if (subject != null) {
+            subjectMap.put(subjectCode, subject);
+            return subject;
+        }
+        subject = new ExamSubject();
+        subject.setExamId(examId);
+        subject.setCode(subjectCode);
+        subject.setName(subjectName);
+        subject.setPaperFileType(FormatType.JSON);
+        subject.setAnswerFileType(FormatType.JSON);
+        subject.setObjectiveScore(0d);
+        subject.setSubjectiveScore(0d);
+        subject.setTotalScore(0d);
+        subject.setUploadCount(0);
+        subjectService.save(subject);
+        subjectMap.put(subjectCode, subject);
+
+        double totalScore = 0d;
+        List<ExamQuestion> list = new ArrayList<>();
+        for (int i = 0; i < questionArray.size(); i++) {
+            JSONObject questionJson = questionArray.getJSONObject(i);
+            int mainNumber = questionJson.getInt("number");
+            String mainTitle = questionJson.getString("name");
+            JSONArray qArray = questionJson.getJSONArray("questions");
+            for (int j = 0; j < qArray.size(); j++) {
+                JSONObject sub = qArray.getJSONObject(j);
+                JSONArray subJson = sub.getJSONArray("subQuestions");
+                if (!subJson.isEmpty()) {
+
+                } else {
+                    ExamQuestion q = new ExamQuestion();
+                    q.setExamId(examId);
+                    q.setSubjectCode(subjectCode);
+                    q.setPaperType("#");
+                    q.setObjective(false);
+                    q.setMainNumber(mainNumber);
+                    String subNumber = sub.getString("number");
+                    q.setSubNumber(subNumber);
+                    q.setMainTitle(mainTitle);
+                    q.setGroupNumber(1);
+                    double score = sub.getDouble("score");
+                    q.setTotalScore(score);
+                    q.setIntervalScore(0.5);
+                    totalScore = totalScore + score;
+                    list.add(q);
+                }
+            }
+        }
+        questionService.save(list);
+        MarkGroup group = new MarkGroup(examId, subjectCode, 1, null, totalScore, 0d, null, null,
+                MarkMode.COMMON.toString(), 0, false, false, null);
+        groupService.save(group);
+        return subject;
+    }
+}

+ 243 - 0
stmms-web/src/main/java/cn/com/qmth/stmms/admin/utils/OnlineExamHttpUtil.java

@@ -0,0 +1,243 @@
+package cn.com.qmth.stmms.admin.utils;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cn.com.qmth.stmms.common.signature.SignatureInfo;
+import cn.com.qmth.stmms.common.signature.SignatureType;
+
+public class OnlineExamHttpUtil {
+
+    private static Logger log = LoggerFactory.getLogger(OnlineExamHttpUtil.class);
+
+    /** 默认的编码格式 */
+    public static final String DEFAULT_CHARSET = "UTF-8";
+
+    public static final String CONTENT_TYPE = "Content-Type";
+
+    public static final String APPLICATION_JSON = "application/x-www-form-urlencoded;charset=utf-8";
+
+    public static final String METHOD_POST = "POST";
+
+    public static final String AUTH = "Authorization";
+
+    protected String uri = null;
+
+    protected String accessKey = null;
+
+    protected String accessSecret = null;
+
+    public OnlineExamHttpUtil(String accessKey, String accessSecret, String uri) {
+        this.accessKey = accessKey;
+        this.accessSecret = accessSecret;
+        this.uri = uri;
+    }
+
+    /**
+     * 
+     * @param params
+     *            headers参数
+     * @param datas
+     *            requestParams参数
+     * @return
+     */
+    public String httpAction(Map<String, String> params, Map<String, Object> datas) {
+        String result = null;
+        HttpsURLConnection conn = null;
+        OutputStream os = null;
+        InputStream is = null;
+
+        try {
+
+            // 获取链接
+            URL url = new URL(uri);
+            conn = (HttpsURLConnection) url.openConnection();
+
+            conn.setRequestMethod(METHOD_POST);
+            conn.setRequestProperty(CONTENT_TYPE, APPLICATION_JSON);
+            // 设置鉴权
+            String signature = SignatureInfo.build(SignatureType.SECRET, METHOD_POST, uri, System.currentTimeMillis(),
+                    accessKey, accessSecret);
+            conn.setRequestProperty(AUTH, signature);
+
+            // ssl
+            SSLContext context = SSLContext.getInstance("SSL", "SunJSSE");
+            TrustManager[] tm = new TrustManager[] { new X509TrustManager() {
+
+                @Override
+                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+                }
+
+                @Override
+                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+                }
+
+                @Override
+                public X509Certificate[] getAcceptedIssuers() {
+                    return null;
+                }
+            } };
+            // 初始化
+            context.init(null, tm, new java.security.SecureRandom());
+            // 获取SSLSocketFactory对象
+            SSLSocketFactory ssf = context.getSocketFactory();
+            conn.setSSLSocketFactory(ssf);
+
+            conn.setUseCaches(false);
+            conn.setDoOutput(true);
+
+            // 设置额外的参数
+            if (params != null && !params.isEmpty()) {
+
+                for (Map.Entry<String, String> param : params.entrySet()) {
+                    conn.setRequestProperty(param.getKey(), param.getValue());
+                }
+            }
+            // 创建链接
+            conn.connect();
+            // 设置请求参数
+            if (datas != null) {
+                StringBuilder sb = new StringBuilder();
+                for (Map.Entry<String, Object> data : datas.entrySet()) {
+                    sb.append(data.getKey()).append("=").append(data.getValue()).append("&");
+                }
+                os = conn.getOutputStream();
+                os.write(sb.toString().getBytes());
+                os.flush();
+            }
+
+            result = getResult(conn);
+        } catch (Exception e) {
+            // 操作失败
+            log.error("OnlineExamHttpUtil connection error!", e);
+            e.printStackTrace();
+            return null;
+        } finally {
+            try {
+                if (os != null) {
+                    os.close();
+                    os = null;
+                }
+                if (is != null) {
+                    is.close();
+                    is = null;
+                }
+            } catch (IOException e) {
+                log.error("OnlineExamHttpUtil connection error!", e);
+            }
+
+            if (conn != null) {
+                conn.disconnect();
+                conn = null;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * 获得连接请求的返回数据
+     * 
+     * @param conn
+     * 
+     * @return 字符串
+     */
+    private String getResult(HttpURLConnection conn) throws IOException {
+
+        StringBuilder text = new StringBuilder();
+
+        InputStream is = null;
+        InputStreamReader sr = null;
+        BufferedReader br = null;
+
+        int code = conn.getResponseCode();
+
+        try {
+            is = code >= 400 ? conn.getErrorStream() : conn.getInputStream();
+
+            sr = new InputStreamReader(is, DEFAULT_CHARSET);
+            br = new BufferedReader(sr);
+
+            char[] chars = new char[4096];
+            int length = 0;
+
+            while ((length = br.read(chars)) != -1) {
+                text.append(chars, 0, length);
+            }
+        } finally {
+            if (br != null) {
+                br.close();
+                br = null;
+            }
+            if (sr != null) {
+                sr.close();
+                sr = null;
+            }
+            if (is != null) {
+                is.close();
+                is = null;
+            }
+        }
+        if (code >= 400) {
+            throw new IOException(text.toString());
+        }
+        return text.toString();
+    }
+
+    public static void main(String[] args) throws IOException {
+        Map<String, Object> datas = new HashMap<String, Object>();
+        datas.put("examId", "62209205889142784");
+        String url = "https://test1.online-exam-test.cn/api/open/exam/course/query";
+        OnlineExamHttpUtil subjectHttp = new OnlineExamHttpUtil("123456", "123", url);
+        String subjectJson = subjectHttp.httpAction(null, datas);
+        System.out.println(subjectJson);
+
+        datas.put("courseCode", "A0001");
+        url = "https://test1.online-exam-test.cn/api/open/exam/record/need_mark";
+        OnlineExamHttpUtil studentHttp = new OnlineExamHttpUtil("123456", "123", url);
+        String studentJson = studentHttp.httpAction(null, datas);
+        System.out.println(studentJson);
+
+        // datas.put("id", "62212585906769920");
+        // url = "https://test1.online-exam-test.cn/api/open/exam/paper/detail";
+        // OnlineExamHttpUtil paperHttp = new OnlineExamHttpUtil("123456",
+        // "123", url);
+        // String paperJson = paperHttp.httpAction(null, datas);
+        // System.out.println(paperJson);
+        //
+        // ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+        // IOUtils.copy(new
+        // ByteArrayInputStream(paperJson.getBytes(StandardCharsets.UTF_8)),
+        // buffer);
+        // byte[] data = buffer.toByteArray();
+        // File target = new File("/Users/ting.yin/Desktop/test123.json");
+        // target.getParentFile().mkdirs();
+        // FileOutputStream ous = new FileOutputStream(target);
+        // ous.write(data);
+        // IOUtils.closeQuietly(ous);
+    }
+}