Browse Source

联考版-迭代

xiaof 4 years ago
parent
commit
3ec362b7b6
28 changed files with 659 additions and 73 deletions
  1. 40 28
      stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/LoginInterceptor.java
  2. 18 8
      stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/api/AuthApi.java
  3. 5 1
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/ParamApi.java
  4. 3 0
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/UserApi.java
  5. 28 8
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/WorkApi.java
  6. 19 10
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/exporter/ScoreExporter.java
  7. 44 12
      stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/service/DataUploadService.java
  8. 1 0
      stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/api/CollectApi.java
  9. 59 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/config/DbConfig.java
  10. 9 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/AesUtil.java
  11. 63 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/DbBackupUtils.java
  12. 40 0
      stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/ServletUtil.java
  13. 13 0
      stmms-ms-core/pom.xml
  14. 55 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/cache/CacheService.java
  15. 10 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/Paper.java
  16. 23 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/ParamSetting.java
  17. 10 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/task/MarkTask.java
  18. 10 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/MarkUser.java
  19. 2 0
      stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkUserRepo.java
  20. 32 1
      stmms-ms-log/src/main/java/cn/com/qmth/stmms/ms/log/aop/MarkLogAop.java
  21. 2 0
      stmms-ms-main/src/main/java/cn/com/qmth/stmms/ms/Application.java
  22. 10 3
      stmms-ms-main/src/main/resources/application-dev.properties
  23. 45 0
      stmms-ms-main/src/main/resources/ehcache.xml
  24. 41 0
      stmms-ms-main/src/test/java/CacheTest.java
  25. 47 0
      stmms-ms-main/src/test/java/backupDb.java
  26. 5 1
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/PaperApi.java
  27. 1 1
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/assembler/PaperAssembler.java
  28. 24 0
      stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/service/AssignTaskService.java

+ 40 - 28
stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/LoginInterceptor.java

@@ -1,12 +1,15 @@
 package cn.com.qmth.stmms.ms.accesscontrol;
 
 import cn.com.qmth.stmms.ms.accesscontrol.config.LoginConfig;
+import cn.com.qmth.stmms.ms.commons.utils.AesUtil;
+import cn.com.qmth.stmms.ms.core.cache.CacheService;
 import cn.com.qmth.stmms.ms.core.domain.user.AbstractUser;
 import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
 import cn.com.qmth.stmms.ms.core.domain.user.Role;
 import cn.com.qmth.stmms.ms.core.repository.MarkUserRepo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
+import org.springframework.util.StringUtils;
 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
 import javax.servlet.http.HttpServletRequest;
@@ -21,38 +24,47 @@ public class LoginInterceptor extends HandlerInterceptorAdapter {
     @Autowired
     private LoginConfig loginConfig;
 
+    @Autowired
+    private CacheService cacheService;
+
     @Override
     public boolean preHandle(HttpServletRequest request,
                              HttpServletResponse response, Object handler) throws Exception {
-        String token = (String) request.getSession().getAttribute("token");
-        if (token != null) {
-            String[] strs = token.split("#");
-            String loginName = strs[1];
-            if (loginConfig.adminLoginConfig().getLoginName().equals(loginName)
-//                    || loginConfig.inspectionLoginConfig().getLoginName().equals(loginName)
-            ) {
-                return true;
-            }
-//            else if (loginConfig.clientLoginConfig().getLoginName().equals(loginName)) {
-//                response.sendError(HttpStatus.UNAUTHORIZED.value(), "该账户只能在采集端登录");
-//                return false;
-//            }
-//            else if (loginConfig.uploadLoginConfig().getLoginName().equals(loginName)) {
-//                response.sendError(HttpStatus.UNAUTHORIZED.value(), "该账户只能在图片客户端登录");
-//                return false;
-//            }
-            AbstractUser user = markUserRepo.findByLoginName(loginName);
-            if (Objects.equals(Role.COLLECTOR, ((MarkUser) user).getRole())) {
-                response.sendError(HttpStatus.UNAUTHORIZED.value(), "该账户只能在采集端登录");
-                return false;
-            }
-            String sessionId = request.getSession().getId();
-            if (user.getSessionId().equalsIgnoreCase(sessionId)) {
-                return true;
-            }
+        String authorization = request.getHeader("Authorization");
+        if(StringUtils.isEmpty(authorization)){
+            authorization = request.getParameter("Authorization");
+        }
+        String userId = request.getHeader("userId");
+        if(StringUtils.isEmpty(userId)){
+            userId = request.getParameter("userId");
+        }
+        String token = cacheService.queryTokenCache(userId);
+        if (StringUtils.isEmpty(authorization) || StringUtils.isEmpty(userId) || StringUtils.isEmpty(token)) {
+            response.sendError(HttpStatus.UNAUTHORIZED.value(), null);
+            return false;
+        }
+        String tokenDec = AesUtil.decoder(token, "token", null);
+        String[] strs = tokenDec.split("#");
+        String loginName = strs[1];
+        if (loginConfig.adminLoginConfig().getLoginName().equals(loginName)) {
+            return true;
+        }
+        AbstractUser user = markUserRepo.findOne(Long.valueOf(userId));
+        if (Objects.equals(Role.COLLECTOR, ((MarkUser) user).getRole())) {
+            response.sendError(HttpStatus.UNAUTHORIZED.value(), "该账户只能在采集端登录");
+            return false;
+        }
+
+        if(!Objects.equals(Role.QC, ((MarkUser) user).getRole()) && !authorization.equals(token)){
+            response.sendError(HttpStatus.UNAUTHORIZED.value(), "该账号在其它地方登录");
+            return false;
+        }
+
+        String sessionId = request.getSession().getId();
+        if (user.getSessionId().equalsIgnoreCase(sessionId)) {
+            return true;
         }
-        response.sendError(HttpStatus.UNAUTHORIZED.value(), "没有登录或会话超时");
-        return false;
+        return true;
     }
 
     public void postHandle(HttpServletRequest request,

+ 18 - 8
stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/api/AuthApi.java

@@ -1,6 +1,8 @@
 package cn.com.qmth.stmms.ms.accesscontrol.api;
 
 import cn.com.qmth.stmms.ms.accesscontrol.config.LoginConfig;
+import cn.com.qmth.stmms.ms.commons.utils.AesUtil;
+import cn.com.qmth.stmms.ms.core.cache.CacheService;
 import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
 import cn.com.qmth.stmms.ms.core.domain.user.Role;
 import cn.com.qmth.stmms.ms.core.repository.MarkUserRepo;
@@ -25,14 +27,18 @@ public class AuthApi {
     @Autowired
     private MarkUserRepo markUserRepo;
 
+    @Autowired
+    private CacheService cacheService;
+
     @RequestMapping(value = "/login", method = RequestMethod.POST)
-    public MarkUser login(MarkUser user, HttpServletRequest request) {
+    public MarkUser login(MarkUser user, HttpServletRequest request) throws Exception {
         MarkUser domain = null;
 
 
         if (loginConfig.adminLoginConfig().getLoginName().equals(user.getLoginName()) &&
                 loginConfig.adminLoginConfig().getPassword().equals(user.getPassword())) {
             domain = new MarkUser(loginConfig.adminLoginConfig().getLoginName(), loginConfig.adminLoginConfig().getPassword(), null, null, "系统管理员", Role.ADMIN, null);
+            domain.setId(0l);
         }
 //        else if (loginConfig.clientLoginConfig().getLoginName().equals(user.getLoginName()) &&
 //                loginConfig.clientLoginConfig().getPassword().equals(user.getPassword())) {
@@ -75,14 +81,18 @@ public class AuthApi {
             domain.setSessionId(request.getSession().getId());
             markUserRepo.save(domain);
         }
-        HttpSession session = request.getSession();
-        String token = (String) request.getSession().getAttribute("token");
-        if (!StringUtils.isEmpty(token)) {
-            session.setAttribute("token", null);
-        }
+//        HttpSession session = request.getSession();
+//        String token = (String) request.getSession().getAttribute("token");
+//        if (!StringUtils.isEmpty(token)) {
+//            session.setAttribute("token", null);
+//        }
         //session过期时间
-        session.setMaxInactiveInterval(-1);
-        session.setAttribute("token", System.currentTimeMillis() + "#" + domain.getLoginName() + "#" + domain.getId());
+//        session.setMaxInactiveInterval(-1);
+        String token = System.currentTimeMillis() + "#" + domain.getLoginName() + "#" + domain.getId();
+        token = AesUtil.encoder(token, "token", null);
+//        session.setAttribute("token", System.currentTimeMillis() + "#" + domain.getLoginName() + "#" + domain.getId());
+        cacheService.saveTokenCache(domain.getId().toString(), token);
+        domain.setToken(token);
         return domain;
     }
 

+ 5 - 1
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/ParamApi.java

@@ -121,7 +121,9 @@ public class ParamApi {
                                            @RequestParam Integer autoCallback,
                                            @RequestParam Integer majority,
                                            @RequestParam Integer cumulativeError,
-                                           @RequestParam Integer levelShowAllPaper) {
+                                           @RequestParam Integer levelShowAllPaper,
+                                           @RequestParam Integer propDenominator,
+                                           @RequestParam Integer autoCallbackShowDeviation) {
         List<MarkSubject> markSubjects = markSubjectRepo.findByWorkIdAndTestNotIn(workId, Arrays.asList(TrialEnum.DEFAULT.ordinal(), TrialEnum.START_FORMAL.ordinal()));
         int countMarkTasks = markTaskRepo.countByWorkId(workId);
         boolean flag = false;
@@ -145,6 +147,8 @@ public class ParamApi {
         paramSetting.setMajority(majority);
         paramSetting.setCumulativeError(cumulativeError);
         paramSetting.setLevelShowAllPaper(levelShowAllPaper);
+        paramSetting.setPropDenominator(propDenominator);
+        paramSetting.setAutoCallbackShowDeviation(autoCallbackShowDeviation);
         paramSettingRepo.saveAndFlush(paramSetting);
         ParamCache.resetParam(paramSetting);
 

+ 3 - 0
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/UserApi.java

@@ -80,6 +80,7 @@ public class UserApi {
         domain.setOneClickLevel(user.getOneClickLevel());
         domain.setStandardVolume(user.getStandardVolume());
         domain.setLevelCallback(user.getLevelCallback());
+        domain.setLeaderConfirm(user.getLeaderConfirm());
         markUserRepo.save(domain);
     }
 
@@ -102,6 +103,7 @@ public class UserApi {
             user.setOneClickLevel(false);
             user.setStandardVolume(false);
             user.setLevelCallback(false);
+            user.setLeaderConfirm(false);
         }
         markUserRepo.save(user);
     }
@@ -163,6 +165,7 @@ public class UserApi {
         user.setOneClickLevel(false);
         user.setStandardVolume(false);
         user.setLevelCallback(false);
+        user.setLeaderConfirm(false);
         markUserRepo.save(user);
     }
 

+ 28 - 8
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/api/WorkApi.java

@@ -17,7 +17,9 @@ import org.springframework.web.bind.annotation.*;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -107,18 +109,36 @@ public class WorkApi {
     @Transactional
     @RequestMapping(value = "{workId}", method = RequestMethod.PUT)
     public Work update(@PathVariable Long workId, @RequestBody Work work) {
-        /*List<MarkSubject> subjects = markSubjectRepo.findAllByWorkId(workId);
-        long count = subjects.stream().filter(m->m.getStage().ordinal() != 0).count();
-        if(count > 0){
-            throw new RuntimeException("档位参数只能采集阶段修改");
-        }*/
+        List<MarkSubject> subjects = markSubjectRepo.findAllByWorkId(workId);
+        long count = subjects.stream().filter(m -> m.getStage().ordinal() != 0).count();
+        List<Level> levels = work.getLevels();
+        if (count > 0) {
+            List<Level> levelList = levelRepo.findByWorkId(workId);
+            Map<String, Level> levelMap = levelList.stream().collect(Collectors.toMap(Level::getCode, Function.identity()));
+            if (levels.size() != levelList.size()) {
+                throw new RuntimeException("开始分档后,不允许增加或删除档位");
+            }
+            for (Level level : levels) {
+                Level oldLevel = levelMap.get(level.getCode());
+                if (oldLevel == null) {
+                    throw new RuntimeException("开始分档后,不允许增加或删除档位");
+                }
+                if (level.getMinScore().intValue() != oldLevel.getMinScore().intValue()
+                        || level.getMaxScore().intValue() != oldLevel.getMaxScore().intValue()
+                        || level.getIntervalScore() != oldLevel.getIntervalScore()
+                        || level.getWeight().intValue() != oldLevel.getWeight().intValue()
+                        || !level.getLevelType().equals(oldLevel.getLevelType())) {
+                    throw new RuntimeException("开始分档后,只允许修改阈值");
+                }
+            }
+        }
 
         levelRepo.deleteByWorkId(work.getId());
 
         //根据A~Z排序后,重新设置levelValue
-        List<Level> levels = work.getLevels();
+
         AtomicInteger ai = new AtomicInteger(0);
-        levels.stream().sorted(Comparator.comparing(Level::getCode)).map(l->{
+        levels.stream().sorted(Comparator.comparing(Level::getCode)).map(l -> {
             l.setId(null);
             l.setLevelValue(ai.getAndIncrement());
             return l;
@@ -189,7 +209,7 @@ public class WorkApi {
     @RequestMapping(value = "{work}/overview", method = RequestMethod.GET)
     public WorkOverview overview(@PathVariable Work work) {
         //生成随机数,已生成的工作,直接跳过
-        if(randomUtil.getRandomMap().get(work.getId()) == null) {
+        if (randomUtil.getRandomMap().get(work.getId()) == null) {
             randomUtil.getRandom(work.getId(), false);
         }
         return workOverviewAssembler.toDTO(work);

+ 19 - 10
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/exporter/ScoreExporter.java

@@ -35,6 +35,7 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
 
 /**
  * Created by zhengmin on 2017/1/18.
@@ -210,7 +211,7 @@ public class ScoreExporter {
      * @param workId
      * @param subjectMap
      */
-    public Sheet drawExcelFixedHeadLevel(int type, Sheet sheet, CellStyle style, Row row, Map<String, Map<String, ExportLevelResultDTO>> subjectMap, Long workId) {
+    public Sheet drawExcelFixedHeadLevel(int type, Sheet sheet, CellStyle style, Row row, Map<String, Map<String, ExportLevelResultDTO>> subjectMap, Long workId, Map<String, String> markSubjectMap) {
         //准考证号
         Cell cell = row.createCell(0);
         cell.setCellValue(EXAM_NUMBER);
@@ -245,7 +246,7 @@ public class ScoreExporter {
             }
             int scSumCount  = level + size + 5;
             Cell cell4 = row.createCell(level);
-            cell4.setCellValue(SC_NAME);
+            cell4.setCellValue(markSubjectMap.get(Subject.SC.toString()));
             cell4.setCellStyle(style);
             if (level != scSumCount) {
                 CellRangeAddress region5 = new CellRangeAddress(0, 0, (short) level, scSumCount);
@@ -261,7 +262,7 @@ public class ScoreExporter {
             }
             int smSumCount = scSumCount + size + 5;//最终列+1,因为从0开始
             Cell cell7 = row.createCell(scSumCount);
-            cell7.setCellValue(SM_NAME);
+            cell7.setCellValue(markSubjectMap.get(Subject.SM.toString()));
             cell7.setCellStyle(style);
             if (scSumCount != smSumCount) {
                 CellRangeAddress region6 = new CellRangeAddress(0, 0, (short) scSumCount, smSumCount);
@@ -276,7 +277,7 @@ public class ScoreExporter {
             }
             int sxSumCount = smSumCount + size + 5;//最终列+1,因为从0开始
             Cell cell8 = row.createCell(smSumCount);
-            cell8.setCellValue(SX_NAME);
+            cell8.setCellValue(markSubjectMap.get(Subject.SX.toString()));
             cell8.setCellStyle(style);
             if (smSumCount != sxSumCount) {
                 CellRangeAddress region9 = new CellRangeAddress(0, 0, (short) smSumCount, sxSumCount);
@@ -318,7 +319,7 @@ public class ScoreExporter {
      * @param workId
      * @param subjectMap
      */
-    public Sheet drawExcelFixedHead(int type, Sheet sheet, CellStyle style, Row row, Map<String, Map<String, ExportLevelResultDTO>> subjectMap, Long workId) {
+    public Sheet drawExcelFixedHead(int type, Sheet sheet, CellStyle style, Row row, Map<String, Map<String, ExportLevelResultDTO>> subjectMap, Long workId, Map<String, String> markSubjectMap) {
         //准考证号
         Cell cell = row.createCell(0);
         cell.setCellValue(EXAM_NUMBER);
@@ -372,7 +373,7 @@ public class ScoreExporter {
                 scSumCount = score + size;
             }
             Cell cell6 = row.createCell(score);
-            cell6.setCellValue(SC_NAME);
+            cell6.setCellValue(markSubjectMap.get(Subject.SC.toString()));
             cell6.setCellStyle(style);
             if (score != scSumCount) {
                 CellRangeAddress region7 = new CellRangeAddress(0, 0, (short) score, scSumCount);
@@ -393,7 +394,7 @@ public class ScoreExporter {
                 smSumCount = scSumCount + size;
             }
             Cell cell7 = row.createCell(scSumCount);
-            cell7.setCellValue(SM_NAME);
+            cell7.setCellValue(markSubjectMap.get(Subject.SM.toString()));
             cell7.setCellStyle(style);
             if (scSumCount != smSumCount) {
                 CellRangeAddress region8 = new CellRangeAddress(0, 0, (short) scSumCount, smSumCount);
@@ -413,7 +414,7 @@ public class ScoreExporter {
                 sxSumCount = smSumCount + size;
             }
             Cell cell8 = row.createCell(smSumCount);
-            cell8.setCellValue(SX_NAME);
+            cell8.setCellValue(markSubjectMap.get(Subject.SX.toString()));
             cell8.setCellStyle(style);
             if (smSumCount != sxSumCount) {
                 CellRangeAddress region9 = new CellRangeAddress(0, 0, (short) smSumCount, sxSumCount);
@@ -489,8 +490,12 @@ public class ScoreExporter {
             style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); //垂直居中
             Row row = sheet.createRow(0);
 
+            // 科目名称
+            List<MarkSubject> markSubjectList = markSubjectRepo.findAllByWorkId(workId);
+            Map<String, String> markSubjectMap = markSubjectList.stream().collect(Collectors.toMap(m->m.getSubject().name(), MarkSubject::getName));
+
             //绘制固定表头
-            sheet = drawExcelFixedHeadLevel(levelInterval, sheet, style, row, subjectMap, workId);
+            sheet = drawExcelFixedHeadLevel(levelInterval, sheet, style, row, subjectMap, workId, markSubjectMap);
 
             //绘制动态表头
             Row dynamicHeadRow = sheet.createRow(1);
@@ -665,8 +670,12 @@ public class ScoreExporter {
             style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); //垂直居中
             Row row = sheet.createRow(0);
 
+            // 科目名称
+            List<MarkSubject> markSubjectList = markSubjectRepo.findAllByWorkId(workId);
+            Map<String, String> markSubjectMap = markSubjectList.stream().collect(Collectors.toMap(m -> m.getSubject().name(), MarkSubject::getName));
+
             //绘制固定表头
-            sheet = drawExcelFixedHead(scoreInterval, sheet, style, row, subjectMap, workId);
+            sheet = drawExcelFixedHead(scoreInterval, sheet, style, row, subjectMap, workId, markSubjectMap);
 
             //绘制动态表头
             Row dynamicHeadRow = sheet.createRow(1);

+ 44 - 12
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/service/DataUploadService.java

@@ -27,6 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.interceptor.TransactionAspectSupport;
+import org.springframework.util.CollectionUtils;
 
 import javax.imageio.ImageIO;
 import java.awt.image.BufferedImage;
@@ -241,6 +242,7 @@ public class DataUploadService {
             throw new Exception("已有采集数据,不能导入考生数据");
         }
         examQuestionRepo.deleteByWorkId(workId);
+        List<Student> studentList = new ArrayList<>();
 
         ExcelReader excelReader = new ExcelReader(StudentDTO.class);
         List<ExcelError> excelErrors = excelReader.reader(inputStream, new ExcelReaderHandle() {
@@ -282,7 +284,8 @@ public class DataUploadService {
                         if (imageConfig.isCustomSubject()) {
                             student.setUploadStatus("CUSTOM:0");
                         }
-                        studentRepo.save(student);
+//                        studentRepo.save(student);
+                        studentList.add(student);
                     } else if (student != null) {
                         if (isAbsent) {
                             student.setAbsent(isAbsent);
@@ -312,7 +315,8 @@ public class DataUploadService {
                             student.setSourceName(dto.getSourceName());
                             student.setSchool(dto.getSchool());
                         }
-                        studentRepo.save(student);
+//                        studentRepo.save(student);
+                        studentList.add(student);
                     }
                     return null;
                 } catch (RuntimeException e) {
@@ -325,9 +329,24 @@ public class DataUploadService {
             }
         });
         String errors = errorsString(excelErrors);
-        if(errors.length() > 0) {
+        if (errors.length() > 0) {
             throw new Exception(errors);
         }
+
+        if (!CollectionUtils.isEmpty(studentList)) {
+            List<Student> data = new ArrayList<>();
+            for (Student stu : studentList) {
+                if (data.size() == 2000) {
+                    studentRepo.save(data);
+                    data.clear();
+                }
+                data.add(stu);
+            }
+            //将剩下的数据也导入
+            if (!data.isEmpty()) {
+                studentRepo.save(data);
+            }
+        }
         return excelErrors;
     }
 
@@ -347,7 +366,7 @@ public class DataUploadService {
             throw new Exception("没有此工作区,请检查workId是否正确");
         }
         List<Paper> papers = paperRepo.findByWorkIdAndSubject(workId, subject);
-        if(papers.isEmpty() || papers.size() == 0){
+        if (papers.isEmpty() || papers.size() == 0) {
             throw new Exception("没有采集数据,不能导入试评数据");
         }
         List<MarkSubject> markSubjectList = work.getSubjects().stream().filter(o -> o.getId().toUpperCase().contains(subject.toString().toUpperCase()))
@@ -370,6 +389,10 @@ public class DataUploadService {
         paperRepo.deleteByWorkIdAndSubjectAndTest(workId, subject, TrialEnum.INIT.getId());
         long startTime = System.currentTimeMillis();
         ExcelReader excelReader = new ExcelReader(StudentDTO.class);
+
+        List<Student> studentList = new ArrayList<>();
+        List<Paper> paperList = new ArrayList<>();
+
         List<ExcelError> excelErrors = excelReader.reader(inputStream, new ExcelReaderHandle() {
 
             @Override
@@ -429,7 +452,8 @@ public class DataUploadService {
                     BeanUtils.copyProperties(student, studentNew);
                     studentNew.setId(null);
                     studentNew.setTest(jsonObject.toJSONString());
-                    studentRepo.save(studentNew);
+//                    studentRepo.save(studentNew);
+                    studentList.add(studentNew);
 
                     Paper paperNew = new Paper();
                     BeanUtils.copyProperties(paper, paperNew);
@@ -447,7 +471,8 @@ public class DataUploadService {
                     paperNew.setSecretNumber(new StringBuffer(String.valueOf(subject.ordinal())).append(questionNew.getAreaCode()).append(random).toString());
                     paperNew.setActive(true);
                     paperNew.setBatchNo(startTime);
-                    paperRepo.save(paperNew);
+//                    paperRepo.save(paperNew);
+                    paperList.add(paperNew);
                 } catch (Exception e) {
                     ExcelError excelError = new ExcelError();
                     excelError.setExcelErrorType(e.getMessage());
@@ -456,11 +481,17 @@ public class DataUploadService {
                 return null;
             }
         });
+        if (!CollectionUtils.isEmpty(studentList)) {
+            studentRepo.save(studentList);
+        }
+        if (!CollectionUtils.isEmpty(paperList)) {
+            paperRepo.save(paperList);
+        }
         if (Objects.nonNull(excelErrors) && excelErrors.size() > 0) {
             TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
         }
         String errors = errorsString(excelErrors);
-        if(errors.length() > 0) {
+        if (errors.length() > 0) {
             throw new Exception(errors);
         }
         return excelErrors;
@@ -492,7 +523,7 @@ public class DataUploadService {
         paper.setUploadedOn(new Date());
         paper.setManual(isManual);
 
-        if(Objects.nonNull(level) && level != ""){
+        if (Objects.nonNull(level) && level != "") {
             paper.setLevel(level);
             //设置为已发布任务的状态
             paper.setActive(true);
@@ -500,7 +531,7 @@ public class DataUploadService {
             paper.setBatchNo(1l);
         }
 
-        if(!imageServerConfig.isAliyunOss()) {
+        if (!imageServerConfig.isAliyunOss()) {
             String sheetPath = null;
             String slicePath = null;
             String fileName = student.getExamNumber();
@@ -593,7 +624,7 @@ public class DataUploadService {
             }
         });
         String errors = errorsString(excelErrors);
-        if(errors.length() > 0) {
+        if (errors.length() > 0) {
             throw new Exception(errors);
         }
         return excelErrors;
@@ -653,13 +684,14 @@ public class DataUploadService {
 
     /**
      * 拼接导入异常信息
+     *
      * @param excelErrors
      * @return
      */
     private String errorsString(List<ExcelError> excelErrors) {
         StringJoiner sj = new StringJoiner(";");
-        if(!excelErrors.isEmpty() && excelErrors.size() > 0){
-            int forint = excelErrors.size() < 10 ? excelErrors.size() : 9 ;
+        if (!excelErrors.isEmpty() && excelErrors.size() > 0) {
+            int forint = excelErrors.size() < 10 ? excelErrors.size() : 9;
             for (int i = 0; i < forint; i++) {
                 ExcelError excelError = excelErrors.get(i);
                 StringBuffer sb = new StringBuffer();

+ 1 - 0
stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/api/CollectApi.java

@@ -271,6 +271,7 @@ public class CollectApi {
             }
         }
         dto.setUploadTime(sdf.format(new Date()));
+        paper.setRelate(!StringUtils.equals(student.getExamNumber(), student.getRelateExamNumber()));
         if (paper != null) {
             dto.setPaperId(paper.getId());
         }

+ 59 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/config/DbConfig.java

@@ -0,0 +1,59 @@
+package cn.com.qmth.stmms.ms.commons.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @Description: 数据库参数
+ */
+@Configuration
+@ConfigurationProperties(prefix = "db", ignoreUnknownFields = false)
+public class DbConfig {
+
+    private String host;
+    private String port;
+    private String dbName;
+    private String userName;
+    private String password;
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public String getPort() {
+        return port;
+    }
+
+    public void setPort(String port) {
+        this.port = port;
+    }
+
+    public String getDbName() {
+        return dbName;
+    }
+
+    public void setDbName(String dbName) {
+        this.dbName = dbName;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

+ 9 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/AesUtil.java

@@ -2,6 +2,7 @@ package cn.com.qmth.stmms.ms.commons.utils;
 
 import cn.com.qmth.stmms.ms.commons.constant.SystemConstant;
 import org.slf4j.LoggerFactory;
+import org.springframework.util.StringUtils;
 
 import javax.crypto.Cipher;
 import javax.crypto.spec.IvParameterSpec;
@@ -18,6 +19,8 @@ import java.util.Base64;
 public class AesUtil {
     private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(AesUtil.class);
 
+    private static final String RULE = "123456790abcdefg";
+
     /**
      * 加密
      *
@@ -79,6 +82,9 @@ public class AesUtil {
      * @throws Exception
      */
     public static String encoder(String content, String encryptKey, String rule) throws Exception {
+        if(StringUtils.isEmpty(rule)){
+            rule = RULE;
+        }
         LOGGER.info("AES加密前的内容:{},key:{}", content, encryptKey);
         String encoderText = Base64.getEncoder().encodeToString(encrypt(content, encryptKey, rule));
         LOGGER.info("AES加密后的文本:{}", encoderText);
@@ -95,6 +101,9 @@ public class AesUtil {
      * @throws Exception
      */
     public static String decoder(String encryptStr, String decryptKey, String rule) throws Exception {
+        if(StringUtils.isEmpty(rule)){
+            rule = RULE;
+        }
         LOGGER.info("AES解密前的内容:{},key:{}", encryptStr, decryptKey);
         String decoderText = decrypt(Base64.getDecoder().decode(encryptStr), decryptKey, rule);
         LOGGER.info("AES解密后的文本:{}", decoderText);

+ 63 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/DbBackupUtils.java

@@ -0,0 +1,63 @@
+package cn.com.qmth.stmms.ms.commons.utils;
+
+import cn.com.qmth.stmms.ms.commons.config.DbConfig;
+import org.apache.http.client.utils.DateUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Date;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * @Date: 2021/5/31.
+ */
+@Component
+public class DbBackupUtils {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(DbBackupUtils.class);
+
+    ExecutorService service = Executors.newFixedThreadPool(1);
+
+    @Autowired
+    DbConfig dbConfig;
+
+    public void startBackup() {
+        service.submit(dbBackUp());
+    }
+
+    public Runnable dbBackUp() {
+        return () -> {
+            String pathSql = dbConfig.getDbName() + DateUtils.formatDate(new Date(), "yyyyMMddHHmmss") + ".sql";
+            File fileSql = new File(pathSql);
+            try {
+                //创建备份sql文件
+                if (!fileSql.exists()) {
+                    fileSql.createNewFile();
+                }
+                //mysqldump -hlocalhost -uroot -p123456 db > /home/back.sql
+                StringBuffer sb = new StringBuffer();
+                sb.append("mysqldump");
+                sb.append(" -h " + dbConfig.getHost());
+                sb.append(" -u" + dbConfig.getUserName());
+                sb.append(" -p" + dbConfig.getPassword());
+                sb.append(" " + dbConfig.getDbName() + " >");
+                sb.append(pathSql);
+                LOGGER.info("cmd命令为:{},开始备份数据库:" + sb.toString(), dbConfig.getDbName());
+                Runtime runtime = Runtime.getRuntime();
+                Process process = runtime.exec("cmd /c" + sb.toString());
+                LOGGER.info("备份成功!");
+            } catch (IOException e) {
+                LOGGER.info("备份失败!原因:{}", e.getMessage());
+            }
+        };
+    }
+
+    public static void main(String[] args) {
+        System.out.println(System.getProperty("os.name"));
+    }
+}

+ 40 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/ServletUtil.java

@@ -0,0 +1,40 @@
+package cn.com.qmth.stmms.ms.commons.utils;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @Date: 2021/5/31.
+ */
+public class ServletUtil {
+
+    /**
+     * 获取HttpServletRequest
+     *
+     * @return
+     */
+    public static HttpServletRequest getRequest() {
+        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+        return servletRequestAttributes.getRequest();
+    }
+
+    /**
+     * 获取用户ID
+     * @return
+     */
+    public static String getUserId() {
+        HttpServletRequest request = getRequest();
+        return request.getHeader("userId");
+    }
+
+    /**
+     * 获取工作ID
+     * @return
+     */
+    public static String getWordId() {
+        HttpServletRequest request = getRequest();
+        return request.getHeader("wordId");
+    }
+}

+ 13 - 0
stmms-ms-core/pom.xml

@@ -25,5 +25,18 @@
             <groupId>cn.com.qmth</groupId>
             <artifactId>stmms-ms-commons</artifactId>
         </dependency>
+
+        <!--开启 cache 缓存 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-cache</artifactId>
+        </dependency>
+
+        <!-- ehcache缓存 -->
+        <dependency>
+            <groupId>net.sf.ehcache</groupId>
+            <artifactId>ehcache</artifactId>
+            <version>2.10.6</version><!--$NO-MVN-MAN-VER$ -->
+        </dependency>
     </dependencies>
 </project>

+ 55 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/cache/CacheService.java

@@ -0,0 +1,55 @@
+package cn.com.qmth.stmms.ms.core.cache;
+
+import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
+import cn.com.qmth.stmms.ms.core.repository.MarkUserRepo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+/**
+ * @Date: 2021/6/1.
+ */
+@Service
+public class CacheService {
+
+    @Autowired
+    MarkUserRepo markUserRepo;
+
+    //这里的单引号不能少,否则会报错,被识别是一个对象
+    private static final String CACHE_NAME = "tokens";
+
+    /**
+     * 保存
+     * @param userId
+     * @return
+     */
+    @CachePut(value = CACHE_NAME, key = "'token' + #userId")
+    public String saveTokenCache(String userId, String token) {
+        return token;
+    }
+
+    /**
+     * 删除
+     * @param userId
+     * @return
+     */
+    @CacheEvict(value = CACHE_NAME, key = "'token' + #userId")
+    public String deleteTokenCache(String userId) {
+        return null;
+    }
+
+
+    /**
+     * 查询
+     * @param userId
+     * @return
+     */
+    @Cacheable(value=CACHE_NAME,key="'token'+ #userId")
+    public String queryTokenCache(String userId){
+        //若找不到缓存将打印出提示语句
+        System.err.println("没有走缓存!"+ userId);
+        return null;
+    }
+}

+ 10 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/Paper.java

@@ -142,6 +142,8 @@ public class Paper implements Serializable {
 
     private Boolean isRejectedByLeader;
 
+    private boolean isRelate;
+
     public int getTest() {
         return test;
     }
@@ -536,4 +538,12 @@ public class Paper implements Serializable {
     public void setRejectedByLeader(Boolean rejectedByLeader) {
         isRejectedByLeader = rejectedByLeader;
     }
+
+    public boolean isRelate() {
+        return isRelate;
+    }
+
+    public void setRelate(boolean relate) {
+        isRelate = relate;
+    }
 }

+ 23 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/ParamSetting.java

@@ -42,6 +42,11 @@ public class ParamSetting implements Serializable {
 
     private Integer scoreShowAllPaper;
 
+    private Integer propDenominator;
+
+    private Integer autoCallbackShowDeviation;
+
+
     public static ParamSetting init(){
         ParamSetting paramSetting = new ParamSetting();
         paramSetting.setPackageScan(0);
@@ -56,6 +61,8 @@ public class ParamSetting implements Serializable {
         paramSetting.setRoundUp(1);
         paramSetting.setChangeStage(0);
         paramSetting.setScoreShowAllPaper(0);
+        paramSetting.setPropDenominator(1);
+        paramSetting.setAutoCallbackShowDeviation(1);
         return paramSetting;
     }
 
@@ -170,4 +177,20 @@ public class ParamSetting implements Serializable {
     public void setScoreShowAllPaper(Integer scoreShowAllPaper) {
         this.scoreShowAllPaper = scoreShowAllPaper;
     }
+
+    public Integer getPropDenominator() {
+        return propDenominator;
+    }
+
+    public void setPropDenominator(Integer propDenominator) {
+        this.propDenominator = propDenominator;
+    }
+
+    public Integer getAutoCallbackShowDeviation() {
+        return autoCallbackShowDeviation;
+    }
+
+    public void setAutoCallbackShowDeviation(Integer autoCallbackShowDeviation) {
+        this.autoCallbackShowDeviation = autoCallbackShowDeviation;
+    }
 }

+ 10 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/task/MarkTask.java

@@ -98,6 +98,8 @@ public class MarkTask implements Serializable {
     //是否标准卷
     private boolean isSample;
 
+    private String deviationDirection;
+
     public Long getBatchNo() {
         return batchNo;
     }
@@ -350,4 +352,12 @@ public class MarkTask implements Serializable {
     public void setSample(boolean sample) {
         isSample = sample;
     }
+
+    public String getDeviationDirection() {
+        return deviationDirection;
+    }
+
+    public void setDeviationDirection(String deviationDirection) {
+        this.deviationDirection = deviationDirection;
+    }
 }

+ 10 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/domain/user/MarkUser.java

@@ -47,6 +47,8 @@ public class MarkUser extends AbstractUser {
 
     private boolean levelCallback;
 
+    private boolean leaderConfirm;
+
     private Integer displayCount;
 
     private Boolean defaultAccount;
@@ -59,6 +61,14 @@ public class MarkUser extends AbstractUser {
         this.levelCallback = levelCallback;
     }
 
+    public boolean getLeaderConfirm() {
+        return leaderConfirm;
+    }
+
+    public void setLeaderConfirm(boolean leaderConfirm) {
+        this.leaderConfirm = leaderConfirm;
+    }
+
     public static long getSerialVersionUID() {
         return serialVersionUID;
     }

+ 2 - 0
stmms-ms-core/src/main/java/cn/com/qmth/stmms/ms/core/repository/MarkUserRepo.java

@@ -25,4 +25,6 @@ public interface MarkUserRepo extends JpaRepository<MarkUser,Long>, JpaSpecifica
 	long countByWorkIdAndRole(Long workId,Role role);
 
 	List<MarkUser> findByRole(Role role);
+
+    List<MarkUser> findByWorkIdAndSubject(Long workId, Subject subject);
 }

+ 32 - 1
stmms-ms-log/src/main/java/cn/com/qmth/stmms/ms/log/aop/MarkLogAop.java

@@ -3,6 +3,7 @@ package cn.com.qmth.stmms.ms.log.aop;
 import cn.com.qmth.stmms.ms.commons.config.LevelConfig;
 import cn.com.qmth.stmms.ms.commons.constant.ArbitrateCallback;
 import cn.com.qmth.stmms.ms.commons.constant.ArbitrateResult;
+import cn.com.qmth.stmms.ms.commons.utils.AesUtil;
 import cn.com.qmth.stmms.ms.commons.utils.SqlUtil;
 import cn.com.qmth.stmms.ms.core.cache.ParamCache;
 import cn.com.qmth.stmms.ms.core.domain.*;
@@ -14,6 +15,7 @@ import cn.com.qmth.stmms.ms.marking.config.MarkingConfig;
 import cn.com.qmth.stmms.ms.marking.dto.MarkTaskDTO;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import org.apache.commons.lang.StringUtils;
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.annotation.AfterReturning;
 import org.aspectj.lang.annotation.Aspect;
@@ -90,6 +92,9 @@ public class MarkLogAop {
     @Resource
     MarkTaskJobRepo markTaskJobRepo;
 
+    @Autowired
+    LevelRepo levelRepo;
+
     /**
      * 标准卷、定档、档位打回切入点
      */
@@ -283,6 +288,10 @@ public class MarkLogAop {
             markTaskJobRepo.updateMarkTaskJobByVersion(markTaskJob.getId(), markTaskJob.getVersion());
             return;
         }
+
+        List<Level> levels = levelRepo.findByWorkId(paper.getWorkId());
+        Map<String, Integer> levelMap = levels.stream().collect(Collectors.toMap(Level::getCode, Level::getLevelValue));
+
         Map<Long, String> levelsMap = markTasks.stream().collect(Collectors.toMap(MarkTask::getMarkerId, o -> o.getResult().toUpperCase()));
         LOGGER.info("this:{} markLogAop异步回调进来了", this);
         arbitrateCallback.judge(levelsMap, deviation, new ArbitrateResult() {
@@ -298,6 +307,7 @@ public class MarkLogAop {
                     for (ArbitrateCallback.Distance d : list) {
                         for (MarkTask m : markTasks) {
                             if (Objects.equals(String.valueOf(d.getC()), m.getResult()) && d.getMarkId().longValue() == m.getMarkerId().longValue()) {
+                                m.setDeviationDirection(calcDeviationDirection(levelMap, m.getResult(), m.getLevel()));
                                 m.setRejected(true);
                                 m.setOriginLevel(m.getResult());
                                 m.setResult(null);
@@ -325,6 +335,25 @@ public class MarkLogAop {
         LOGGER.info("this:{} markLogAop异步回调结束了", this);
     }
 
+    /**
+     * 计算偏差方向
+     *
+     * @param levelMap
+     * @param result   定档档位
+     * @param level    评卷员打的档位
+     * @return
+     */
+    private String calcDeviationDirection(Map<String, Integer> levelMap, String result, String level) {
+        if (StringUtils.isNotBlank(result) && StringUtils.isNotBlank(level)) {
+            Integer resultInt = levelMap.get(result);
+            Integer levelInt = levelMap.get(level);
+            if (resultInt != null && levelInt != null) {
+                return String.valueOf(levelInt.intValue() - levelInt.intValue());
+            }
+        }
+        return null;
+    }
+
     /**
      * 查询处于哪个档位公用
      *
@@ -369,10 +398,12 @@ public class MarkLogAop {
         ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
         HttpServletRequest request = attributes.getRequest();
         HttpSession session = request.getSession();
-        String token = (String) session.getAttribute(TOKEN);
+//        String token = (String) session.getAttribute(TOKEN);
+        String token = request.getHeader("Authorization");
         if (Objects.isNull(token)) {
             throw new Exception("请先登录");
         }
+        token = AesUtil.decoder(token, "token", null);
         Object[] args = joinPoint.getArgs(); // 参数值
         MarkTask markTask = null;
         MarkUser markUser = null;

+ 2 - 0
stmms-ms-main/src/main/java/cn/com/qmth/stmms/ms/Application.java

@@ -3,6 +3,7 @@ package cn.com.qmth.stmms.ms;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
@@ -23,6 +24,7 @@ import java.io.File;
 @EnableTransactionManagement
 @EnableAsync
 @EnableScheduling
+@EnableCaching
 public class Application {
 
     public static void main(String[] args) throws Exception {

+ 10 - 3
stmms-ms-main/src/main/resources/application-dev.properties

@@ -2,9 +2,15 @@
 #spring.datasource.username=root
 #spring.datasource.password=root
 
-spring.datasource.url=jdbc:mysql://localhost:3306/chuanyin-2020-v1.0_1?useUnicode=true&characterEncoding=UTF-8
-spring.datasource.username=root
-spring.datasource.password=root
+db.host=localhost
+db.port=3306
+db.dbName=msyj-2.0.0
+db.userName=root
+db.password=root
+
+spring.datasource.url=jdbc:mysql://${db.host}:${db.port}/${db.dbName}?useUnicode=true&characterEncoding=UTF-8
+spring.datasource.username=${db.userName}
+spring.datasource.password=${db.password}
 
 spring.datasource.validation-query=SELECT 1 FROM DUAL
 spring.datasource.test-on-borrow=true
@@ -29,6 +35,7 @@ spring.jpa.hibernate.ddl-auto=update
 
 spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
 spring.jackson.time-zone=GMT+8
+spring.cache.ehcache.config=classpath:ehcache.xml
 
 
 spring.http.multipart.max-file-size=10Mb

+ 45 - 0
stmms-ms-main/src/main/resources/ehcache.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
+         updateCheck="false">
+
+    <!-- diskStore:ehcache其实是支持内存+磁盘+堆外内存,几个层级的缓存 -->
+    <!-- 在这里设置一下,但是一般不用的 -->
+    <diskStore path="java.io.tmpdir/Tmp_EhCache" />
+
+    <!-- defaultCache,是默认的缓存策略 -->
+    <!-- 如果你指定的缓存策略没有找到,那么就用这个默认的缓存策略 -->
+    <!-- external:如果设置为true的话,那么timeout就没有效果,缓存就会一直存在,一般默认就是false -->
+    <!-- maxElementsInMemory:内存中可以缓存多少个缓存条目,在实践中,你是需要自己去计算的,比如你计算你要缓存的对象是什么?有多大?最多可以缓存多少MB,或者多少个G的数据?除以每个对象的大小,计算出最多可以放多少个对象 -->
+    <!-- overflowToDisk:如果内存不够的时候,是否溢出到磁盘 -->
+    <!-- diskPersistent:是否启用磁盘持久化的机制,在jvm崩溃的时候和重启之间,不用 -->
+    <!-- timeToIdleSeconds:对象最大的闲置的时间,如果超出闲置的时间,可能就会过期,我们这里就不用了,缓存最多闲置5分钟就被干掉了 -->
+    <!-- timeToLiveSeconds:对象最多存活的时间,我们这里也不用,超过这个时间,缓存就过期,就没了 -->
+    <!-- memoryStoreEvictionPolicy:当缓存数量达到了最大的指定条目数的时候,需要采用一定的算法,从缓存中清除一批数据,LRU,最近最少使用算法,最近一段时间内,最少使用的那些数据,就被干掉了 -->
+    <defaultCache
+            eternal="false"
+            maxElementsInMemory="1000"
+            overflowToDisk="false"
+            diskPersistent="false"
+            timeToIdleSeconds="0"
+            timeToLiveSeconds="0"
+            memoryStoreEvictionPolicy="LRU" />
+
+    <!-- 手动指定的缓存策略 -->
+    <!-- 比如你一个应用吧,可能要缓存很多种不同的数据,比如说商品信息,或者是其他的一些数据 -->
+    <!-- 对不同的数据,缓存策略可以在这里配置多种 -->
+    <cache
+            name="tokens"
+            eternal="false"
+            maxElementsInMemory="1000"
+            overflowToDisk="false"
+            diskPersistent="false"
+            timeToIdleSeconds="300"
+            timeToLiveSeconds="0"
+            memoryStoreEvictionPolicy="LRU" />
+
+    <!-- ehcache这种东西,简单实用,是很快速的,1小时上手可以用在项目里了,没什么难度的 -->
+    <!-- ehcache这个技术,如果讲深了,里面的东西还是很多的,高级的feature,但是我们这里就不涉及了 -->
+
+</ehcache>
+

+ 41 - 0
stmms-ms-main/src/test/java/CacheTest.java

@@ -0,0 +1,41 @@
+import cn.com.qmth.stmms.ms.Application;
+import cn.com.qmth.stmms.ms.core.cache.CacheService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @Date: 2021/5/27.
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = {Application.class})
+public class CacheTest {
+
+    @Autowired
+    CacheService cacheService;
+
+    @Test
+    public void test() {
+
+        String token1 = cacheService.queryTokenCache("68");
+        System.out.println("token1:" + token1);
+
+        String token2 = cacheService.saveTokenCache("68", "sc1");
+        System.out.println("token2:" + token2);
+
+        String token3 = cacheService.queryTokenCache("68");
+        System.out.println("token3:" + token3);
+
+        String token4 = cacheService.deleteTokenCache("68");
+        System.out.println("token4:" + token4);
+
+        String token5 = cacheService.queryTokenCache("68");
+        System.out.println("token5:" + token5);
+    }
+}

+ 47 - 0
stmms-ms-main/src/test/java/backupDb.java

@@ -0,0 +1,47 @@
+import cn.com.qmth.stmms.ms.Application;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @Date: 2021/5/27.
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = {Application.class})
+public class backupDb {
+    @Test
+    public void backupDb() throws Exception {
+        String backName = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date())+".sql";
+        dbBackUp("root","root","msyj-2.0.0","D:\\",backName);
+
+    }
+
+    //mysqldump -h端口号 -u用户 -p密码 数据库 > d:/test.sql --备份D盘
+    //备份
+    public static void dbBackUp(String root, String pwd, String dbName, String backPath, String backName) throws Exception {
+        String pathSql = backPath + backName;
+        File fileSql = new File(pathSql);
+        //创建备份sql文件
+        if (!fileSql.exists()) {
+            fileSql.createNewFile();
+        }
+        //mysqldump -hlocalhost -uroot -p123456 db > /home/back.sql
+        StringBuffer sb = new StringBuffer();
+        sb.append("mysqldump");
+        sb.append(" -h127.0.0.1");
+        sb.append(" -u" + root);
+        sb.append(" -p" + pwd);
+        sb.append(" " + dbName + " >");
+        sb.append(pathSql);
+        System.out.println("cmd命令为:" + sb.toString());
+        Runtime runtime = Runtime.getRuntime();
+        System.out.println("开始备份:" + dbName);
+        Process process = runtime.exec("cmd /c" + sb.toString());
+        System.out.println("备份成功!");
+    }
+}

+ 5 - 1
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/api/PaperApi.java

@@ -143,6 +143,7 @@ public class PaperApi {
                                      @RequestParam(required = false) Long endNumber,
                                      @RequestParam(required = false) Boolean isManual,
                                      @RequestParam(required = false) Boolean missing,
+                                     @RequestParam(required = false) Boolean isRelate,
                                      @RequestParam(required = false) String studentName,
                                      @RequestParam(required = false) String sortBy,
                                      Pageable pageable) {
@@ -176,6 +177,9 @@ public class PaperApi {
             if (missing != null) {
                 predicates.add(builder.equal(root.get("isMissing"), missing));
             }
+            if (isRelate != null) {
+                predicates.add(builder.equal(root.get("isRelate"), isRelate));
+            }
             //考生姓名
             if (studentName != null && studentName != "") {
                 predicates.add(builder.equal(root.get("studentName"), studentName));
@@ -257,7 +261,7 @@ public class PaperApi {
         papers.forEach(p -> {
             paperDTOs.add(paperAssembler.toDTO(p));
         });
-        paperDTOs.sort(Comparator.comparingInt(PaperDTO::getSortSum));
+        paperDTOs.sort((o1, o2) -> o2.getSortSum() -o1.getSortSum());
         return new PageableDTO(paperDTOs, papers.getTotalElements(), papers.getTotalPages(), pageable.getPageNumber());
     }
 

+ 1 - 1
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/assembler/PaperAssembler.java

@@ -125,7 +125,7 @@ public class PaperAssembler {
                 } else {
                     List<Level> levels = levelRepo.findByWorkId(paper.getWorkId());
                     if (!levels.isEmpty() && levels.size() > 0) {
-                        Map<String, Integer> map = levels.stream().collect(Collectors.toMap(Level::getCode, Level::getLevelValue));
+                        Map<String, Integer> map = levels.stream().collect(Collectors.toMap(Level::getCode, Level::getWeight));
                         List<MarkTask> markTaskList = markTaskRepo.findByPaperIdAndStage(paper.getId(), MarkStage.LEVEL);
                         int sum = markTaskList.stream().mapToInt(m -> map.get(m.getResult()) == null ? 0 : map.get(m.getResult())).sum();
                         paperDTO.setSortSum(sum);

+ 24 - 0
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/service/AssignTaskService.java

@@ -1,17 +1,22 @@
 package cn.com.qmth.stmms.ms.marking.service;
 
+import cn.com.qmth.stmms.ms.commons.utils.DbBackupUtils;
 import cn.com.qmth.stmms.ms.commons.utils.RandomUtil;
+import cn.com.qmth.stmms.ms.commons.utils.ServletUtil;
 import cn.com.qmth.stmms.ms.commons.utils.SqlUtil;
+import cn.com.qmth.stmms.ms.core.cache.CacheService;
 import cn.com.qmth.stmms.ms.core.domain.*;
 import cn.com.qmth.stmms.ms.core.domain.task.MarkTask;
 import cn.com.qmth.stmms.ms.core.domain.user.MarkUser;
 import cn.com.qmth.stmms.ms.core.domain.user.MarkerGroup;
+import cn.com.qmth.stmms.ms.core.domain.user.Role;
 import cn.com.qmth.stmms.ms.core.repository.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 
 import java.util.*;
 import java.util.function.Function;
@@ -51,6 +56,15 @@ public class AssignTaskService {
     @Autowired
     SqlUtil sqlUtil;
 
+    @Autowired
+    DbBackupUtils dbBackupUtils;
+
+    @Autowired
+    CacheService cacheService;
+
+    @Autowired
+    MarkUserRepo markUserRepo;
+
     /**
      * 单评任务模式,每个科目评卷员都需要对该科目每份试卷进行评卷
      * 比如,色彩有1000份试卷,那么每个评卷员都需要评1000份
@@ -269,6 +283,16 @@ public class AssignTaskService {
             initTaskPublishData(markSubject);
 
         }
+
+        // 所有用户强制退出
+        List<MarkUser> userList = markUserRepo.findByWorkIdAndSubject(markSubject.getWorkId(), markSubject.getSubject());
+        userList = userList.stream().filter(m-> Role.MARKER.equals(m.getRole()) || Role.MARK_LEADER.equals(m.getRole())).collect(Collectors.toList());
+        if(!CollectionUtils.isEmpty(userList)){
+            for (MarkUser user : userList) {
+                cacheService.deleteTokenCache(user.getId().toString());
+            }
+        }
+        dbBackupUtils.startBackup();
     }
 
     private void initTaskPublishData(MarkSubject markSubject) {