소스 검색

档案系统四性检测文件摘要

lvy 2 일 전
부모
커밋
03d25013aa

+ 8 - 1
blade-service-api/blade-business-api/src/main/java/org/springblade/business/entity/ArchiveFile.java

@@ -348,8 +348,15 @@ public class ArchiveFile extends BaseEntity {
     @ApiModelProperty("-1:检测无误,0:未检测,1:无日期,2:无责任者,3:dpi小于300,4:pdf有遮挡或者污渍")
     private Integer checkStatus;
 
-
+    /**
+     * fileUrl md5值
+     */
+    @ApiModelProperty("fileUrl md5值")
     private String fileMd5;
+    /**
+     * pdfFileUrl md5值
+     */
+    @ApiModelProperty("pdfFileUrl md5值")
     private String pdfMd5;
 
     public void fromExternal(ArchiveFileVo vo) {

+ 300 - 0
blade-service-api/blade-business-api/src/main/java/org/springblade/business/utils/DigestUtil.java

@@ -0,0 +1,300 @@
+package org.springblade.business.utils;
+
+import java.io.*;
+import java.math.BigInteger;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * 扩展的摘要算法工具类
+ * 新增对文件流、网络资源等的摘要计算支持
+ */
+public class DigestUtil {
+
+    private static final int BUFFER_SIZE = 8192;
+
+
+    /**
+     * 计算本地文件的MD5摘要
+     * @param filePath 文件路径
+     * @return 文件的MD5摘要
+     */
+    public static String md5OfFile(String filePath) throws IOException {
+        return digestOfFile(filePath, "MD5");
+    }
+
+    /**
+     * 计算本地文件的SHA-256摘要
+     * @param filePath 文件路径
+     * @return 文件的SHA-256摘要
+     */
+    public static String sha256OfFile(String filePath) throws IOException {
+        return digestOfFile(filePath, "SHA-256");
+    }
+
+    /**
+     * 计算本地文件的指定算法摘要
+     * @param filePath 文件路径
+     * @param algorithm 摘要算法
+     * @return 文件的摘要
+     */
+    public static String digestOfFile(String filePath, String algorithm) throws IOException {
+        Path path = Paths.get(filePath);
+        try (InputStream fis = Files.newInputStream(path)) {
+            return digestOfStream(fis, algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("不支持的摘要算法: " + algorithm, e);
+        }
+    }
+
+    /**
+     * 计算MultipartFile的MD5摘要
+     * @param multipartFile MultipartFile对象
+     * @return 文件的MD5摘要
+     */
+    public static String md5OfMultipartFile(org.springframework.web.multipart.MultipartFile multipartFile) throws IOException {
+        return digestOfMultipartFile(multipartFile, "MD5");
+    }
+
+    /**
+     * 计算MultipartFile的SHA-256摘要
+     * @param multipartFile MultipartFile对象
+     * @return 文件的SHA-256摘要
+     */
+    public static String sha256OfMultipartFile(org.springframework.web.multipart.MultipartFile multipartFile) throws IOException {
+        return digestOfMultipartFile(multipartFile, "SHA-256");
+    }
+
+    /**
+     * 计算MultipartFile的指定算法摘要
+     * @param multipartFile MultipartFile对象
+     * @param algorithm 摘要算法
+     * @return 文件的摘要
+     */
+    public static String digestOfMultipartFile(org.springframework.web.multipart.MultipartFile multipartFile, String algorithm) throws IOException {
+        try (InputStream inputStream = multipartFile.getInputStream()) {
+            return digestOfStream(inputStream, algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("不支持的摘要算法: " + algorithm, e);
+        }
+    }
+
+    /**
+     * 计算网络文件的MD5摘要
+     * @param fileUrl 网络文件URL
+     * @return 文件的MD5摘要
+     */
+    public static String md5OfUrl(String fileUrl) throws IOException {
+        return digestOfUrl(fileUrl, "MD5");
+    }
+
+    /**
+     * 计算网络文件的SHA-256摘要
+     * @param fileUrl 网络文件URL
+     * @return 文件的SHA-256摘要
+     */
+    public static String sha256OfUrl(String fileUrl) throws IOException {
+        return digestOfUrl(fileUrl, "SHA-256");
+    }
+
+    /**
+     * 计算网络文件的指定算法摘要
+     * @param fileUrl 网络文件URL
+     * @param algorithm 摘要算法
+     * @return 文件的摘要
+     */
+    public static String digestOfUrl(String fileUrl, String algorithm) throws IOException {
+        URL url = new URL(fileUrl);
+        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+        connection.setRequestMethod("GET");
+        connection.connect();
+
+        try (InputStream inputStream = connection.getInputStream()) {
+            return digestOfStream(inputStream, algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("不支持的摘要算法: " + algorithm, e);
+        } finally {
+            connection.disconnect();
+        }
+    }
+
+    /**
+     * 计算输入流的指定算法摘要
+     * @param inputStream 输入流
+     * @param algorithm 摘要算法
+     * @return 流的摘要
+     */
+    public static String digestOfStream(InputStream inputStream, String algorithm) throws IOException, NoSuchAlgorithmException {
+        MessageDigest md = MessageDigest.getInstance(algorithm);
+        try (DigestInputStream dis = new DigestInputStream(inputStream, md)) {
+            byte[] buffer = new byte[BUFFER_SIZE];
+            while (dis.read(buffer) != -1) {
+                // 读取数据的同时自动更新摘要
+            }
+        }
+        return bytesToHex(md.digest());
+    }
+
+
+    /**
+     * 计算大文件的摘要(适用于内存受限情况)
+     * @param filePath 文件路径
+     * @param algorithm 摘要算法
+     * @return 文件的摘要
+     */
+    public static String digestOfLargeFile(String filePath, String algorithm) throws IOException {
+        Path path = Paths.get(filePath);
+        try (FileChannel channel = FileChannel.open(path);
+             InputStream inputStream = Channels.newInputStream(channel)) {
+            return digestOfStream(inputStream, algorithm);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("不支持的摘要算法: " + algorithm, e);
+        }
+    }
+
+    /**
+     * MD5摘要算法
+     * @param input 输入字符串
+     * @return 32位MD5摘要
+     */
+    public static String md5(String input) {
+        return digest(input, "MD5");
+    }
+
+    /**
+     * SHA-1摘要算法
+     * @param input 输入字符串
+     * @return SHA-1摘要
+     */
+    public static String sha1(String input) {
+        return digest(input, "SHA-1");
+    }
+
+    /**
+     * SHA-256摘要算法
+     * @param input 输入字符串
+     * @return SHA-256摘要
+     */
+    public static String sha256(String input) {
+        return digest(input, "SHA-256");
+    }
+
+    /**
+     * SHA-512摘要算法
+     * @param input 输入字符串
+     * @return SHA-512摘要
+     */
+    public static String sha512(String input) {
+        return digest(input, "SHA-512");
+    }
+
+    /**
+     * 通用摘要算法
+     * @param input 输入字符串
+     * @param algorithm 算法名称 MD5, SHA-1, SHA-256, SHA-512 ....
+     * @return 指定算法的摘要
+     */
+    private static String digest(String input, String algorithm) {
+        try {
+            MessageDigest md = MessageDigest.getInstance(algorithm);
+            byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
+            return bytesToHex(hashBytes);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("不支持的摘要算法: " + algorithm, e);
+        }
+    }
+
+    /**
+     * 通用摘要算法
+     * @param input 输入字符串
+     * @param algorithm 算法名称
+     * @return 指定算法的摘要
+     */
+    public static String digest(byte[] input, String algorithm) {
+        try {
+            MessageDigest md = MessageDigest.getInstance(algorithm);
+            byte[] hashBytes = md.digest(input);
+            return bytesToHex(hashBytes);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("不支持的摘要算法: " + algorithm, e);
+        }
+    }
+
+    /**
+     * 字节数组转十六进制字符串
+     * @param bytes 字节数组
+     * @return 十六进制字符串
+     */
+    public static String bytesToHex(byte[] bytes) {
+        StringBuilder result = new StringBuilder();
+        for (byte b : bytes) {
+            result.append(String.format("%02x", b));
+        }
+        return result.toString();
+    }
+
+    /**
+     * 十六进制字符串转字节数组
+     * @param hex 十六进制字符串
+     * @return 字节数组
+     */
+    public static byte[] hexToBytes(String hex) {
+        int len = hex.length();
+        byte[] data = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
+                    + Character.digit(hex.charAt(i+1), 16));
+        }
+        return data;
+    }
+
+    /**
+     * 字节数组转Base64字符串
+     * @param bytes 字节数组
+     * @return Base64编码字符串
+     */
+    public static String bytesToBase64(byte[] bytes) {
+        return java.util.Base64.getEncoder().encodeToString(bytes);
+    }
+
+    /**
+     * Base64字符串转字节数组
+     * @param base64 Base64编码字符串
+     * @return 字节数组
+     */
+    public static byte[] base64ToBytes(String base64) {
+        return java.util.Base64.getDecoder().decode(base64);
+    }
+
+    /**
+     * 字节数组转十进制字符串
+     * @param bytes 字节数组
+     * @return 十进制字符串表示
+     */
+    public static String bytesToDecimal(byte[] bytes) {
+        BigInteger bi = new BigInteger(1, bytes);
+        return bi.toString(10);
+    }
+
+    /**
+     * 获取指定长度的摘要(截取前length位)
+     * @param input 输入字符串
+     * @param algorithm 算法名称
+     * @param length 截取长度
+     * @return 截取后的摘要
+     */
+    public static String digestWithLength(String input, String algorithm, int length) {
+        String digest = digest(input, algorithm);
+        return digest.substring(0, Math.min(digest.length(), length));
+    }
+}
+

+ 32 - 0
blade-service/blade-business/src/main/java/org/springblade/business/feignClient/ArchiveFileClientImpl.java

@@ -17,9 +17,11 @@ import org.springblade.business.feign.ArchiveFileClient;
 import org.springblade.business.mapper.ArchiveFileMapper;
 import org.springblade.business.service.IArchiveFileService;
 import org.springblade.business.service.ITaskService;
+import org.springblade.business.utils.DigestUtil;
 import org.springblade.business.vo.ArchiveFileVO;
 import org.springblade.common.utils.FileUtils;
 import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.tool.utils.StringUtil;
 import org.springblade.manager.entity.ContractInfo;
 import org.springblade.manager.enums.StorageTypeEnum;
 import org.springblade.manager.feign.ContractClient;
@@ -49,6 +51,9 @@ public class ArchiveFileClientImpl implements ArchiveFileClient {
 
     @Override
     public void saveArchiveFile(ArchiveFileVO vo) {
+        if (vo.getList() != null) {
+            vo.getList().forEach(ArchiveFileClientImpl::digestMd5);
+        }
         this.iArchiveFileService.saveArchiveFile(vo.getList());
     }
 
@@ -281,6 +286,9 @@ public class ArchiveFileClientImpl implements ArchiveFileClient {
 
     @Override
     public void addArchiveFile(List<ArchiveFile> files) {
+        for (ArchiveFile file : files) {
+            digestMd5(file);
+        }
         iArchiveFileService.saveBatch(files);
     }
 
@@ -310,6 +318,9 @@ public class ArchiveFileClientImpl implements ArchiveFileClient {
 
     @Override
     public void addArchiveFileEx(List<ArchiveFile> files) {
+        for (ArchiveFile file : files) {
+            digestMd5(file);
+        }
         iArchiveFileService.saveBatch(files);
     }
 
@@ -364,9 +375,27 @@ public class ArchiveFileClientImpl implements ArchiveFileClient {
 
     @Override
     public void saveArchiveFileByBIM(ArchiveFile archiveFile) {
+        digestMd5(archiveFile);
         iArchiveFileService.save(archiveFile);
     }
 
+    private static void digestMd5(ArchiveFile archiveFile) {
+        try {
+            if (StringUtil.isNotBlank(archiveFile.getFileUrl())) {
+                archiveFile.setFileMd5(DigestUtil.md5OfUrl(archiveFile.getFileUrl()));
+            }
+            if (StringUtil.isNotBlank(archiveFile.getPdfFileUrl())) {
+                if (Objects.equals(archiveFile.getPdfFileUrl(), archiveFile.getFileUrl())) {
+                    archiveFile.setPdfMd5(archiveFile.getFileMd5());
+                } else {
+                    archiveFile.setPdfMd5(DigestUtil.md5OfUrl(archiveFile.getPdfFileUrl()));
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
     @Override
     public List<ArchiveFile> getArchiveFileByArchiveIds(String archiveIds) {
         return iArchiveFileService.getArchiveFileByArchivesId(archiveIds,null);
@@ -471,6 +500,9 @@ public class ArchiveFileClientImpl implements ArchiveFileClient {
 
     @Override
     public void saveBatchArchiveFile(List<ArchiveFile> list) {
+        for (ArchiveFile file : list) {
+            digestMd5(file);
+        }
         iArchiveFileService.saveBatch(list);
     }
 

+ 15 - 0
blade-service/blade-business/src/main/java/org/springblade/business/service/impl/ArchiveFileServiceImpl.java

@@ -11,6 +11,7 @@ import org.springblade.archive.feign.ArchiveInspectionInfoClient;
 import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.entity.Task;
 import org.springblade.business.entity.TaskParallel;
+import org.springblade.business.utils.DigestUtil;
 import org.springblade.business.vo.ArchiveFileVO;
 import org.springblade.business.mapper.ArchiveFileMapper;
 import org.springblade.business.service.IArchiveFileService;
@@ -156,6 +157,20 @@ public class ArchiveFileServiceImpl extends BaseServiceImpl<ArchiveFileMapper, A
                 if (list.get(i).getRectification() != null && list.get(i).getRectification() == 1) {
                     list.get(i).setRectification(2);
                 }
+                try {
+                    if (list.get(i).getFileUrl() != null) {
+                        list.get(i).setFileMd5(DigestUtil.md5OfUrl(list.get(i).getFileUrl()));
+                    }
+                    if (list.get(i).getPdfFileUrl() != null) {
+                        if (Objects.equals(list.get(i).getPdfFileUrl(), list.get(i).getFileUrl())) {
+                            list.get(i).setPdfMd5(list.get(i).getFileMd5());
+                        } else {
+                            list.get(i).setPdfMd5(DigestUtil.md5OfUrl(list.get(i).getPdfFileUrl()));
+                        }
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
             }
         }
         // 删除oss文件