Эх сурвалжийг харах

美术阅卷10月新增需求-新增图片加密解密功能

wangliang 5 жил өмнө
parent
commit
730315f9d3

+ 1 - 1
stmms-ms-accesscontrol/src/main/java/cn/com/qmth/stmms/ms/accesscontrol/config/AccessConfig.java

@@ -32,6 +32,6 @@ public class AccessConfig extends WebMvcConfigurerAdapter {
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
         registry.addInterceptor( loginInterceptor()).addPathPatterns("/api/**").excludePathPatterns("/api/admin/users/login",
-                "/api/user/login","/api/user/getClientUser","/api/exam/students","/api/upload/student/*","/api/file/ms-slice/**","/api/subject/collect-config","/api/file/ms-sheet/**");
+                "/api/user/login","/api/user/getClientUser","/api/exam/students","/api/upload/student/*","/api/file/image/**","/api/file/ms-slice/**","/api/subject/collect-config","/api/file/ms-sheet/**");
     }
 }

+ 4 - 3
stmms-ms-admin/src/main/java/cn/com/qmth/stmms/ms/admin/service/DataUploadService.java

@@ -263,8 +263,8 @@ public class DataUploadService {
         int count = 0, result = 0;
         Long random = 0L;
         while (true) {
-//            random = RandomUtil.randomMap.get(workId).get(new Random().nextInt(RandomUtil.randomMap.get(workId).size()));
-            random = RandomUtil.randomList.get(new Random().nextInt(RandomUtil.randomList.size()));
+            random = RandomUtil.randomMap.get(workId).get(new Random().nextInt(RandomUtil.randomMap.get(workId).size()));
+//            random = RandomUtil.randomList.get(new Random().nextInt(RandomUtil.randomList.size()));
             result = paperRepo.countByWorkIdAndExamNumberAndRandomSeq(workId, examNumber, random);
             if (result == 0 && random != Long.parseLong(examNumber.substring(3, examNumber.length()))) {
                 break;
@@ -272,7 +272,8 @@ public class DataUploadService {
                 count++;
             }
             if (count > 100) {
-                throw new Exception("重复几率较高,建议重新生成随机号");
+//                throw new Exception("重复几率较高,建议重新生成随机号");
+                RandomUtil.getRandom(workId, true);
             }
         }
         return random;

+ 178 - 68
stmms-ms-collect/src/main/java/cn/com/qmth/stmms/ms/collect/api/CollectApi.java

@@ -9,7 +9,6 @@ import cn.com.qmth.stmms.ms.commons.config.ImageCompressionConfig;
 import cn.com.qmth.stmms.ms.commons.config.SystemConfig;
 import cn.com.qmth.stmms.ms.commons.constant.SystemConstant;
 import cn.com.qmth.stmms.ms.commons.utils.MD5Util;
-import cn.com.qmth.stmms.ms.commons.utils.PictureUtil;
 import cn.com.qmth.stmms.ms.commons.utils.image.ImageCompression;
 import cn.com.qmth.stmms.ms.core.domain.MarkSubject;
 import cn.com.qmth.stmms.ms.core.domain.Student;
@@ -141,10 +140,69 @@ public class CollectApi {
         return list;
     }
 
-    File srcFile = new File("/Users/king/stmms-ms/static/thumbs/6/SX/1/1901040150.jpg"); //初始文件
+    File srcFile = new File("/Users/king/stmms-ms/static/images/6/SM/1/1901040150.jpg"); //初始文件
 
     /**
-     * 上传图片到服务器(图片加密)
+     * 上传原图(图片加密)
+     *
+     * @param workId
+     * @param subjectId
+     * @param fileName
+     * @param request
+     * @param response
+     * @throws IOException
+     */
+    @RequestMapping(value = "file/image/uploadsheet/{workId}/{subjectId}/{fileName}", method = {RequestMethod.GET})
+    public void imageUploadSheet(@PathVariable Long workId, @PathVariable Integer subjectId,
+                                 @PathVariable String fileName,
+                                 HttpServletRequest request, HttpServletResponse response) throws IOException {
+        long start = System.currentTimeMillis();
+        LOGGER.info("准备生成原图:{}", start);
+        InputStream inputStream = null;
+        OutputStream outputStream = null;
+        try {
+//            inputStream = request.getInputStream();
+            inputStream = new FileInputStream(srcFile);
+            Student student = studentRepo.findByWorkIdAndExamNumber(workId, fileName);
+            Subject subject = Subject.values()[subjectId - 1];
+
+            //保存原图
+            String sheetDir = systemConfig.getSheetDir() + File.separator + workId + File.separator + subject
+                    + File.separator + student.getAreaCode();
+            File out = new File(sheetDir);
+            if (!out.exists()) {
+                out.mkdirs();
+            }
+
+            String imageMd5 = getImageRuleMd5(workId, subject.ordinal(), student.getAreaCode(), student.getExamNumber(), student.getId());
+            File sheetFile = new File(sheetDir + File.separator + imageMd5 + ".jpg");
+            LOGGER.info("sheet存放目录:{}", sheetFile.getPath());
+            outputStream = new FileOutputStream(sheetFile);
+            writeStream(inputStream, outputStream);
+            long end = System.currentTimeMillis();
+            LOGGER.info("生成原图耗时:{}", (end - start) / 1000 + "s");
+
+//            String md5 = request.getHeader("md5");
+//            in = new FileInputStream(imageFile);
+//            String sheetMD5 = DigestUtils.md5Hex(in);
+//            if (!md5.equalsIgnoreCase(sheetMD5)) {
+//                throw new Exception("图片md5值不一致");
+//            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (Objects.nonNull(inputStream)) {
+                inputStream.close();
+            }
+            if (Objects.nonNull(outputStream)) {
+                outputStream.flush();
+                outputStream.close();
+            }
+        }
+    }
+
+    /**
+     * 上传裁切原图和缩略图到服务器(图片加密)
      *
      * @param workId
      * @param subjectId
@@ -157,52 +215,73 @@ public class CollectApi {
     public void imageUpload(@PathVariable Long workId, @PathVariable Integer subjectId,
                             @PathVariable String fileName,
                             HttpServletRequest request, HttpServletResponse response) throws IOException {
+        long start = System.currentTimeMillis();
+        LOGGER.info("准备生成裁切原图和缩略图:{}", start);
         InputStream inputStream = null;
         OutputStream outputStream = null;
+        OutputStream outputStreamTemp = null;
         try {
 //            inputStream = request.getInputStream();
-//            String md5 = request.getHeader("md5");
-            inputStream = PictureUtil.getInput(srcFile);
+            inputStream = new FileInputStream(srcFile);
             Student student = studentRepo.findByWorkIdAndExamNumber(workId, fileName);
             Subject subject = Subject.values()[subjectId - 1];
-            //保存遮盖图+文件名加密
-            String savePath = systemConfig.getImageDir() + File.separator + workId + File.separator + subject
+            //保存裁切原图+文件名加密
+            String imageDir = systemConfig.getImageDir() + File.separator + workId + File.separator + subject
                     + File.separator + student.getAreaCode();
-            File out = new File(savePath);
+            File out = new File(imageDir);
             if (!out.exists()) {
                 out.mkdirs();
             }
 
-            String imageMd5 = getImageRuleMd5(workId, subject.ordinal(), student.getAreaCode(), student.getExamNumber(), student.getId(), SystemConstant.IMAGE);
-//            暂不用Aes加密,因为没用到反解
-//            StringBuffer stringBuffer = new StringBuffer(String.valueOf(workId)).append(subject.ordinal()).append(student.getAreaCode()).append(student.getExamNumber()).append(student.getId()).append(image);
-//            String rule = stringBuffer.toString();
-//            LOGGER.info("rule:{},length:{}", rule, rule.length());
-//            rule = String.format("%016d", Long.parseLong(rule));
-//            LOGGER.info("rule补零后:{},length:{}", rule, rule.length());
-//            String aesStr = AesUtil.encoder(student.getExamNumber(), stringBuffer.toString(), rule);
-//            LOGGER.info("aesStr:{}", aesStr);
-//            File outFile = new File(savePath + File.separator + aesStr + ".jpg");
-            File outFile = new File(savePath + File.separator + imageMd5 + ".jpg");
-            LOGGER.info("image存放目录:{}", outFile.getPath());
-            outputStream = new FileOutputStream(outFile);
-            int dataOfFile = 0;
-            while ((dataOfFile = inputStream.read()) > -1) {
-                outputStream.write(dataOfFile ^ SystemConstant.SECRET_KEY);
+            String imageMd5 = getImageRuleMd5(workId, subject.ordinal(), student.getAreaCode(), student.getExamNumber(), student.getId());
+            File imageFile = new File(imageDir + File.separator + imageMd5 + ".jpg");
+            File imageFileTemp = new File(imageDir + File.separator + imageMd5 + "temp.jpg");
+            LOGGER.info("image存放目录:{}", imageFile.getPath());
+            outputStream = new FileOutputStream(imageFile);
+            outputStreamTemp = new FileOutputStream(imageFileTemp);
+            int index = 0;
+            byte[] bytes = new byte[1024];
+            byte[] bytesEnc = new byte[1024];
+            while ((index = inputStream.read(bytes)) != -1) {
+                //将字节数组的数据全部写入到输出流中
+                for (int i = 0; i < index; i++) {
+                    //通过异或运算加密
+                    bytesEnc[i] = (byte) (bytes[i] ^ SystemConstant.SECRET_KEY);
+                }
+                outputStream.write(bytesEnc, 0, index);
+                outputStreamTemp.write(bytes, 0, index);
             }
 
-            // 生成缩略图
+            //生成缩略图
             String thumbDir = systemConfig.getThumbDir() + File.separator + workId + File.separator + subject
                     + File.separator + student.getAreaCode();
             File thumb = new File(thumbDir);
             if (!thumb.exists()) {
                 thumb.mkdirs();
             }
-            BufferedImage bufferedImage = ImageCompression.compress(outFile, compressionConfig);
-//            String thumbMd5 = getImageRuleMd5(workId, subject.ordinal(), student.getAreaCode(), student.getExamNumber(), student.getId(), SystemConstant.THUMB);
-            File thumbFile = new File(savePath + File.separator + imageMd5 + ".jpg");
-            ImageIO.write(bufferedImage, "jpg", thumbFile);
-//            FileInputStream in = new FileInputStream(outFile);
+
+            BufferedImage bufferedImage = ImageCompression.compress(imageFileTemp, compressionConfig);
+            File thumbFile = new File(thumbDir + File.separator + imageMd5 + ".jpg");
+//            File thumbFileTemp = new File(thumbDir + File.separator + imageMd5 + "temp.jpg");
+            LOGGER.info("thumb存放目录:{}", thumbFile.getPath());
+            outputStream = new FileOutputStream(thumbFile);
+//            outputStreamTemp = new FileOutputStream(thumbFileTemp);
+//            ImageIO.write(bufferedImage, "jpg", outputStreamTemp);
+            ByteArrayOutputStream os = new ByteArrayOutputStream();
+            ImageIO.write(bufferedImage, "gif", os);
+            inputStream = new ByteArrayInputStream(os.toByteArray());
+
+            //原图删除
+            imageFileTemp.delete();
+//            inputStream = PictureUtil.getInput(thumbFileTemp);
+            //缩略图删除
+//            thumbFileTemp.delete();
+            writeStream(inputStream, outputStream);
+            long end = System.currentTimeMillis();
+            LOGGER.info("生成原图和缩略图耗时:{}", (end - start) / 1000 + "s");
+
+//            String md5 = request.getHeader("md5");
+//            FileInputStream in = new FileInputStream(imageFile);
 //            String sliceMD5 = DigestUtils.md5Hex(in);
 //            if (!md5.equalsIgnoreCase(sliceMD5)) {
 //                throw new Exception("图片md5值不一致");
@@ -213,10 +292,14 @@ public class CollectApi {
             if (Objects.nonNull(inputStream)) {
                 inputStream.close();
             }
-            if (Objects.nonNull(inputStream)) {
+            if (Objects.nonNull(outputStream)) {
                 outputStream.flush();
                 outputStream.close();
             }
+            if (Objects.nonNull(outputStreamTemp)) {
+                outputStreamTemp.flush();
+                outputStreamTemp.close();
+            }
         }
     }
 
@@ -235,41 +318,45 @@ public class CollectApi {
     public void imageDownload(@PathVariable Long workId, @PathVariable Integer subjectId,
                               @PathVariable Long studentId, @PathVariable Integer imageType,
                               HttpServletRequest request, HttpServletResponse response) throws IOException {
-        //读取路径下面的文件
-        InputStream in = null;
+        long start = System.currentTimeMillis();
+        LOGGER.info("准备读取图片:{},imageType", start, imageType);
+        InputStream inputStream = null;
         OutputStream outputStream = null;
         try {
+            response.setContentType("image/jpg");
             Student student = studentRepo.findOne(studentId);
             Subject subject = Subject.values()[subjectId - 1];
-            String savePath = systemConfig.getImageDir() + File.separator + workId + File.separator + subject
-                    + File.separator + student.getAreaCode();
-//            暂不用Aes解密,因为没用到反解
-//            StringBuffer stringBuffer = new StringBuffer(String.valueOf(workId)).append(subject.ordinal()).append(student.getAreaCode()).append(student.getExamNumber()).append(student.getId()).append(image);
-//            String savePath = systemConfig.getImageDir() + File.separator + workId + File.separator + subject
-//                    + File.separator + student.getAreaCode();
-//            String rule = stringBuffer.toString();
-//            LOGGER.info("rule:{},length:{}", rule, rule.length());
-//            rule = String.format("%016d", Long.parseLong(rule));
-//            LOGGER.info("rule补零后:{},length:{}", rule, rule.length());
-//            String aesStr = AesUtil.encoder(student.getExamNumber(), stringBuffer.toString(), rule);
-//            String examNumber = AesUtil.decoder(aesStr, stringBuffer.toString(), rule);
-//            LOGGER.info("解密后的文件名称:{}", examNumber);
-            String md5 = getImageRuleMd5(workId, subject.ordinal(), student.getAreaCode(), student.getExamNumber(), student.getId(), imageType);
-//            String ext = file.getName().substring(file.getName().indexOf(".") + 1);
-            //判断图片格式,设置相应的输出文件格式
-//            if (ext.equalsIgnoreCase("jpg")) {
-            response.setContentType("image/jpg");
-//            } else if (ext.equalsIgnoreCase("png")) {
-//                response.setContentType("image/png");
-//            }
-            File file = new File(savePath + File.separator + md5 + ".jpg");
+            String path = null;
+            switch (imageType) {
+                case 1:
+                    //裁切原图
+                    path = systemConfig.getImageDir() + File.separator + workId + File.separator + subject
+                            + File.separator + student.getAreaCode();
+                    break;
+                case 2:
+                    //缩略图
+                    path = systemConfig.getThumbDir() + File.separator + workId + File.separator + subject
+                            + File.separator + student.getAreaCode();
+                    break;
+                case 3:
+                    //原图
+                    path = systemConfig.getSheetDir() + File.separator + workId + File.separator + subject
+                            + File.separator + student.getAreaCode();
+                    break;
+                default:
+                    //分数水印图
+                    path = systemConfig.getSheetDir() + File.separator + workId + File.separator + subject
+                            + File.separator + student.getAreaCode();
+                    break;
+            }
+            String md5 = getImageRuleMd5(workId, subject.ordinal(), student.getAreaCode(), student.getExamNumber(), student.getId());
+            File file = new File(path + File.separator + md5 + ".jpg");
             //读取指定路径下面的文件
-            in = new FileInputStream(file);
+            inputStream = new FileInputStream(file);
             outputStream = new BufferedOutputStream(response.getOutputStream());
-            int dataOfFile = 0;
-            while ((dataOfFile = in.read()) > -1) {
-                outputStream.write(dataOfFile ^ SystemConstant.SECRET_KEY);
-            }
+            writeStream(inputStream, outputStream);
+            long end = System.currentTimeMillis();
+            LOGGER.info("读取图片耗时:{}", (end - start) / 1000 + "s");
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
@@ -279,8 +366,8 @@ public class CollectApi {
                 //关流
                 outputStream.close();
             }
-            if (Objects.nonNull(in)) {
-                in.close();
+            if (Objects.nonNull(inputStream)) {
+                inputStream.close();
             }
         }
     }
@@ -392,17 +479,40 @@ public class CollectApi {
      * @param areaCode
      * @param examNumber
      * @param studentId
-     * @param imageType
      * @return
-     * @throws Exception
      */
-    public String getImageRuleMd5(Long workId, int subjectId, String areaCode, String examNumber, Long studentId, int imageType) throws Exception {
+    public String getImageRuleMd5(Long workId, int subjectId, String areaCode, String examNumber, Long studentId) {
         //暂不用Aes解密,因为没用到反解
-        StringBuffer stringBuffer = new StringBuffer(String.valueOf(workId)).append(subjectId).append(areaCode).append(examNumber).append(studentId).append(imageType);
+        StringBuffer stringBuffer = new StringBuffer(String.valueOf(workId)).append(subjectId).append(areaCode).append(examNumber).append(studentId);
         String rule = stringBuffer.toString();
         LOGGER.info("rule:{},length:{}", rule, rule.length());
-        rule = String.format("%025d", Long.parseLong(rule));
-        LOGGER.info("rule补零后:{},length:{}", rule, rule.length());
+        if (rule.length() < 16) {
+            rule = String.format("%016d", Long.parseLong(rule));
+            LOGGER.info("rule补零后:{},length:{}", rule, rule.length());
+        }
         return MD5Util.encoder(rule);
     }
+
+    /**
+     * 流写入
+     *
+     * @param inputStream
+     * @param outputStream
+     * @return
+     * @throws IOException
+     */
+    public OutputStream writeStream(InputStream inputStream, OutputStream outputStream) throws IOException {
+        int index = 0;
+        byte[] bytes = new byte[1024];
+        byte[] bytesEnc = new byte[1024];
+        while ((index = inputStream.read(bytes)) != -1) {
+            //将字节数组的数据全部写入到输出流中
+            for (int i = 0; i < index; i++) {
+                //通过异或运算加密
+                bytesEnc[i] = (byte) (bytes[i] ^ SystemConstant.SECRET_KEY);
+            }
+            outputStream.write(bytesEnc, 0, index);
+        }
+        return outputStream;
+    }
 }

+ 16 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/constant/SystemConstant.java

@@ -0,0 +1,16 @@
+package cn.com.qmth.stmms.ms.commons.constant;
+
+/**
+ * @Description: 系统常量
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2019/10/11
+ */
+public class SystemConstant {
+    public static final String ENCODING = "UTF-8",
+            AES = "AES",
+            AES_MODE = "AES/CBC/PKCS5Padding";//用这个模式,规则必须为16位
+    //    public static final String AES_RULE = "0102030405060708";
+    public static final int SECRET_KEY = 0x99;//加密解密秘钥
+}

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

@@ -0,0 +1,103 @@
+package cn.com.qmth.stmms.ms.commons.utils;
+
+import cn.com.qmth.stmms.ms.commons.constant.SystemConstant;
+import org.slf4j.LoggerFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.util.Base64;
+
+/**
+ * @Description: AES对称加密
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2019/10/11
+ */
+public class AesUtil {
+    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(AesUtil.class);
+
+    /**
+     * 加密
+     *
+     * @param content
+     * @param strKey
+     * @param rule
+     * @return
+     * @throws Exception
+     */
+    private static byte[] encrypt(String content, String strKey, String rule) throws Exception {
+        SecretKeySpec skeySpec = getKey(strKey);
+        Cipher cipher = Cipher.getInstance(SystemConstant.AES_MODE);
+        IvParameterSpec iv = new IvParameterSpec(rule.getBytes());//AES规则,可自定义,例如A-Z排序
+        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
+        return cipher.doFinal(content.getBytes());
+    }
+
+    /**
+     * 解密
+     *
+     * @param content
+     * @param strKey
+     * @param rule
+     * @return
+     * @throws Exception
+     */
+    private static String decrypt(byte[] content, String strKey, String rule) throws Exception {
+        SecretKeySpec skeySpec = getKey(strKey);
+        Cipher cipher = Cipher.getInstance(SystemConstant.AES_MODE);
+        IvParameterSpec iv = new IvParameterSpec(rule.getBytes());//AES规则,可自定义,例如A-Z排序
+        cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
+        byte[] original = cipher.doFinal(content);
+        return new String(original);
+    }
+
+    /**
+     * 公钥
+     *
+     * @param strKey
+     * @return
+     * @throws Exception
+     */
+    private static SecretKeySpec getKey(String strKey) throws Exception {
+        byte[] arrBTmp = strKey.getBytes();
+        byte[] arrB = new byte[16]; // 创建一个空的16位字节数组(默认值为0)
+        for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
+            arrB[i] = arrBTmp[i];
+        }
+        return new SecretKeySpec(arrB, SystemConstant.AES);
+    }
+
+    /**
+     * AES加密
+     *
+     * @param content
+     * @param encryptKey
+     * @param rule
+     * @return
+     * @throws Exception
+     */
+    public static String encoder(String content, String encryptKey, String rule) throws Exception {
+        LOGGER.info("AES加密前的内容:{},key:{}", content, encryptKey);
+        String encoderText = Base64.getEncoder().encodeToString(encrypt(content, encryptKey, rule));
+        LOGGER.info("AES加密后的文本:{}", encoderText);
+        return encoderText;
+    }
+
+    /**
+     * AES解密
+     *
+     * @param encryptStr
+     * @param decryptKey
+     * @param rule
+     * @return
+     * @throws Exception
+     */
+    public static String decoder(String encryptStr, String decryptKey, String rule) throws Exception {
+        LOGGER.info("AES解密前的内容:{},key:{}", encryptStr, decryptKey);
+        String decoderText = decrypt(Base64.getDecoder().decode(encryptStr), decryptKey, rule);
+        LOGGER.info("AES解密后的文本:{}", decoderText);
+        return decoderText;
+    }
+}

+ 52 - 0
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/MD5Util.java

@@ -0,0 +1,52 @@
+package cn.com.qmth.stmms.ms.commons.utils;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+/**
+ * @Description: MD5加密工具类
+ * @Param:
+ * @return:
+ * @Author: wangliang
+ * @Date: 2019/10/11
+ */
+public class MD5Util {
+    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(MD5Util.class);
+
+    /**
+     * MD5加密
+     *
+     * @param text
+     * @return
+     * @throws Exception
+     */
+    public static String encoder(String text) {
+        text = Optional.of(text).get();
+        LOGGER.info("MD5加密前的文本:{}", text);
+        String encodeStr = DigestUtils.md5Hex(text);
+        LOGGER.info("MD5加密后的文本:{}", encodeStr);
+        return encodeStr;
+    }
+
+    /**
+     * MD5校验
+     *
+     * @param text
+     * @param md5
+     * @return
+     * @throws Exception
+     */
+    public static boolean verify(String text, String md5) {
+        text = Optional.of(text).get();
+        md5 = Optional.of(md5).get();
+        //根据传入的密钥进行验证
+        String md5Text = encoder(text);
+        if (md5Text.equalsIgnoreCase(md5)) {
+            LOGGER.info("MD5验证通过");
+            return true;
+        }
+        return false;
+    }
+}

+ 27 - 24
stmms-ms-commons/src/main/java/cn/com/qmth/stmms/ms/commons/utils/RandomUtil.java

@@ -2,10 +2,7 @@ package cn.com.qmth.stmms.ms.commons.utils;
 
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 
 /**
  * @Description: 随机数生成工具类
@@ -19,8 +16,8 @@ public class RandomUtil {
     public static final int minSize = 1000000;
     public static final int maxSize = 1000001;
     public static final int randomSize = 2000000;
-    //    public static Map<Long, List<Long>> randomMap = new HashMap<>();//用map感觉很占内存
-    public static List<Long> randomList = new ArrayList<>();//改用list
+    public static Map<Long, List<Long>> randomMap = new HashMap<>();
+//    public static List<Long> randomList = new ArrayList<>();
 
     /**
      * 根据workId随机生成百万随机数
@@ -29,24 +26,30 @@ public class RandomUtil {
      * @param againRandom
      */
     public static void getRandom(Long workId, boolean againRandom) {
-        if (randomList.size() > 0) {
-            randomList.clear();
+        List list = randomMap.get(workId);
+        if (Objects.isNull(list)) {
+            randomMap.clear();
+            list = new ArrayList();
+        }
+        if (list.size() == 0 || againRandom) {
+            long start = System.currentTimeMillis();
+            Long randomReq = workId % 10;
+            randomReq = randomReq == 0L ? 1L : randomReq;
+            LOGGER.info("workId:{},开始生成随机数:{}", workId, start);
+            Long finalRandomReq = randomReq;
+            List finalList = list;
+            new Thread(() -> {
+                Set<Long> set = new HashSet<>();
+                for (int i = 0; i < randomSize; i++) {
+                    long id = (long) (Math.random() * minSize + maxSize * finalRandomReq);
+                    set.add(id);
+                }
+                finalList.addAll(set);
+                set.clear();
+                randomMap.put(workId, finalList);
+                long end = System.currentTimeMillis();
+                LOGGER.info("workId:{},生成随机数耗时:{},数据长度为:{}", workId, (end - start) / 1000 + "s", finalList.size());
+            }).start();
         }
-        long start = System.currentTimeMillis();
-        Long randomSeq = workId % 10;
-        randomSeq = randomSeq == 0L ? 1L : randomSeq;
-        LOGGER.info("workId:{},开始生成随机数:{}", workId, start);
-        Long finalRandomSeq = randomSeq;
-        new Thread(() -> {
-            Set<Long> set = new HashSet<>();
-            for (int i = 0; i < randomSize; i++) {
-                long id = (long) (Math.random() * minSize + maxSize * finalRandomSeq);
-                set.add(id);
-            }
-            randomList.addAll(set);
-            set.clear();
-            long end = System.currentTimeMillis();
-            LOGGER.info("workId:{},生成随机数耗时:{},数据长度为:{}", workId, (end - start) / 1000 + "s", randomList.size());
-        }).start();
     }
 }

+ 4 - 3
stmms-ms-marking/src/main/java/cn/com/qmth/stmms/ms/marking/service/AssignTaskService.java

@@ -135,8 +135,8 @@ public class AssignTaskService {
         int count = 0, result = 0;
         Long random = 0L;
         while (true) {
-//            random = RandomUtil.randomMap.get(workId).get(new Random().nextInt(RandomUtil.randomMap.get(workId).size()));
-            random = RandomUtil.randomList.get(new Random().nextInt(RandomUtil.randomList.size()));
+            random = RandomUtil.randomMap.get(workId).get(new Random().nextInt(RandomUtil.randomMap.get(workId).size()));
+//            random = RandomUtil.randomList.get(new Random().nextInt(RandomUtil.randomList.size()));
             result = markTaskRepo.countByMarkerIdAndPaperIdAndWorkIdAndRandomSeqNew(markerId, paperId, workId, random);
             if (result == 0 && random != Long.parseLong(examNumber.substring(3, examNumber.length()))) {
                 break;
@@ -144,7 +144,8 @@ public class AssignTaskService {
                 count++;
             }
             if (count > 100) {
-                throw new Exception("重复几率较高,建议重新生成随机号");
+//                throw new Exception("重复几率较高,建议重新生成随机号");
+                RandomUtil.getRandom(workId, true);
             }
         }
         return random;