Bladeren bron

档案-四性检测
1-1 获取文件数字摘要开发

LHB 5 dagen geleden
bovenliggende
commit
e2532a98b6

+ 20 - 0
blade-service-api/blade-archive-api/src/main/java/org/springblade/archive/vo/ArchiveExaminingVo.java

@@ -12,6 +12,8 @@ import lombok.Data;
 public class ArchiveExaminingVo {
     @ApiModelProperty("项目ID")
     private Long projectId;
+    @ApiModelProperty("合同段ID")
+    private Long contractId;
 
     @ApiModelProperty("报告ID")
     private Long reportId;
@@ -19,12 +21,30 @@ public class ArchiveExaminingVo {
     @ApiModelProperty("真实性")
     private String authenticity;
 
+    @ApiModelProperty("真实性-检测项")
+    private String authenticityList;
+
     @ApiModelProperty("完整性")
     private String integrality;
 
+    @ApiModelProperty("完整性-检测项")
+    private String integralityList;
+
     @ApiModelProperty("可用性")
     private String usability;
 
+    @ApiModelProperty("可用性-检测项")
+    private String usabilityList;
+
     @ApiModelProperty("安全性")
     private String security;
+
+    @ApiModelProperty("安全性-检测项")
+    private String securityList;
+
+    @ApiModelProperty("节点")
+    private String nodeIds;
+
+    @ApiModelProperty("文件")
+    private String fileIds;
 }

+ 230 - 93
blade-service/blade-archive/src/main/java/org/springblade/archive/service/impl/ArchiveExaminingReportImpl.java

@@ -1,15 +1,19 @@
 package org.springblade.archive.service.impl;
 
-import com.alibaba.fastjson.JSON;
-import com.aliyun.oss.OSSClient;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.itextpdf.text.*;
 import com.itextpdf.text.pdf.BaseFont;
 import com.itextpdf.text.pdf.PdfPCell;
 import com.itextpdf.text.pdf.PdfPTable;
 import com.itextpdf.text.pdf.PdfWriter;
 import lombok.AllArgsConstructor;
+import lombok.var;
 import org.apache.commons.lang.StringUtils;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
 import org.springblade.archive.entity.ArchiveExaminingReport;
 import org.springblade.archive.entity.ArchiveExaminingReportDetail;
 import org.springblade.archive.mapper.ArchiveExaminingReportMapper;
@@ -17,29 +21,30 @@ import org.springblade.archive.service.IArchiveExaminingReportDetailService;
 import org.springblade.archive.service.IArchiveExaminingReportService;
 import org.springblade.archive.socket.WebSocketServer;
 import org.springblade.archive.utils.FileUtils;
+import org.springblade.archive.utils.RemoteFileMD5Calculator;
 import org.springblade.archive.vo.ArchiveExaminingSocketVo;
 import org.springblade.archive.vo.ArchiveExaminingVo;
+import org.springblade.archive.vo.ArchivesAutoVO;
 import org.springblade.business.entity.ArchiveFile;
 import org.springblade.business.feign.ArchiveFileClient;
 import org.springblade.common.constant.ArchiveConstant;
 import org.springblade.core.mp.base.BaseServiceImpl;
 import org.springblade.core.oss.model.BladeFile;
-import org.springblade.core.secure.BladeUser;
-import org.springblade.core.secure.utils.AuthUtil;
-import org.springblade.core.secure.utils.SecureUtil;
+import org.springblade.core.tool.utils.CollectionUtil;
 import org.springblade.core.tool.utils.StringUtil;
 import org.springblade.evisa.feign.EVisaClient;
 import org.springblade.evisa.vo.CertBeanVO;
+import org.springblade.manager.feign.ArchiveTreeContractClient;
 import org.springblade.resource.feign.NewIOSSClient;
-import org.springblade.resource.feign.NewISmsClient;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
 import java.util.*;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * @Param
@@ -59,6 +64,10 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
 
     private final EVisaClient eVisaClient;
 
+    private final ArchivesAutoServiceImpl archivesAutoService;
+
+    private final ArchiveTreeContractClient archiveTreeContractClient;
+
     /**
      * 推送状态到前端
      *
@@ -87,6 +96,11 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
 
     }
 
+    public static void main(String[] args) {
+        //检查文件数据摘要
+        RemoteFileMD5Calculator.MD5Result md5Result = RemoteFileMD5Calculator.calculateRemoteFileMD5("https://xinan1.zos.ctyun.cn/blade-oss-chongqing/upload/20250827/ab9cc223fb73cf6267654fd7b63e1a31.pdf");
+        System.out.println(md5Result);
+    }
     /**
      * 四性检测
      *
@@ -99,100 +113,202 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
         report.setId(id);
         report.setStatus(2);
         this.updateById(report);
-        //获取项目中所有档案文件的工序资料pdfUrl
-        List<ArchiveFile> files = archiveFileClient.getAllPdfFileUrlByProjectIdAndFileType(vo.getProjectId());
+
+        //优化 获取权限表示码
+        String authCode = archiveTreeContractClient.getAuthCode(vo.getContractId());
+        //封装查询参数查询
+        ArchivesAutoVO queryVo = new ArchivesAutoVO();
+        queryVo.setProjectId(vo.getProjectId());
+        queryVo.setContractId(vo.getContractId());
+        queryVo.setCurrent(1);
+        queryVo.setSize(999999999);
+        queryVo.setIsArchive(1);
+        queryVo.setAuthCode(authCode);
+        //多个节点查询数据
+        String nodeIds = vo.getNodeIds();
+        Set<String> collect = new HashSet<>();
+        if(StringUtils.isNotEmpty(nodeIds)){
+            for (String s : nodeIds.split(",")) {
+                queryVo.setNodeIds(s);
+                //封装参数查询组卷列表
+                IPage<ArchivesAutoVO> page = archivesAutoService.selectArchivesAutoFilePage(queryVo);
+                List<ArchivesAutoVO> records = page.getRecords();
+                if(CollectionUtil.isNotEmpty(records)){
+                    collect.addAll(records.stream().map(ArchivesAutoVO::getId).map(String::valueOf).collect(Collectors.toSet()));
+                }
+            }
+        }
+        //选中的指定文件也加入进来
+        if(StringUtils.isNotEmpty(vo.getNodeIds())){
+            Set<String> collect1 = Arrays.stream(vo.getNodeIds().split(",")).collect(Collectors.toSet());
+            collect.addAll(collect1);
+        }
+        List<ArchiveFile> files = new ArrayList<>();
+        if(CollectionUtil.isNotEmpty(collect)){
+            //类型转换
+            List<String> strings = new ArrayList<>(collect);
+            //根据组件id查询文件数据
+            files = archiveFileClient.getAllArchiveFileByArchiveIds(strings);
+        }
+
         //不合格对象
         List<Map<String, String>> mapList = new ArrayList<>();
+        //电签验证
         int unqualifiedCount = 0;
+        //3-2 文件是否能够访问
+        int fileIsAccess = 0;
         //检测中
-        //真实性
-        if (StringUtils.isNotBlank(vo.getAuthenticity()) && "1".equals(vo.getAuthenticity())) {
-            //检测项目下所有工序资料PDF签章有效性
+        //文件为空,不允许检测
+        if(CollectionUtil.isNotEmpty(files)){
             for (ArchiveFile file : files) {
-                if (StringUtils.isNotBlank(file.getPdfFileUrl())) {
-                    CertBeanVO cb = eVisaClient.onlineCheckSeal(file.getPdfFileUrl());
-                    if (cb == null) {
-                        Map<String, String> map = new HashMap<>();
-                        map.put("examiningItem", ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对固化信息有效性检测");
-                        map.put("unqualifiedObject", file.getFileName());
-                        mapList.add(map);
-                        unqualifiedCount++;
+                //优先检查文件是否可读
+                if(StringUtils.isEmpty(file.getPdfFileUrl()) || !validateWithHead(file.getPdfFileUrl())){
+                    Map<String, String> map = new HashMap<>();
+                    map.put("examiningItem", ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对电子档案内容数据的可读性检测");
+                    map.put("unqualifiedObject", file.getFileName());
+                    mapList.add(map);
+                    fileIsAccess++;
+                    detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
+                            ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对电子档案内容数据的可读性检测", fileIsAccess, fileIsAccess == 0 ? "无" : "详见附件", fileIsAccess == 0 ? 0 : 1));
+                    continue;
+                }
+                //真实性
+                if (StringUtils.isNotBlank(vo.getAuthenticity()) && "1".equals(vo.getAuthenticity())) {
+                    //获取pdf
+                    //加密pdf
+
+                    if(vo.getAuthenticityList().contains("1")){
+                        //检测项目下所有工序资料PDF签章有效性
+                        CertBeanVO cb = eVisaClient.onlineCheckSeal(file.getPdfFileUrl());
+                        if (cb == null) {
+                            Map<String, String> map = new HashMap<>();
+                            map.put("examiningItem", ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对固化信息有效性检测");
+                            map.put("unqualifiedObject", file.getFileName());
+                            mapList.add(map);
+                            unqualifiedCount++;
+                        }
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对固化信息有效性检测", unqualifiedCount, unqualifiedCount == 0 ? "无" : "详见附件", unqualifiedCount == 0 ? 0 : 1));
+                    }
+                    if(vo.getAuthenticityList().contains("2")){
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对电子文件内容一致性检测", 0, "无", 0));
+                    }
+                    if(vo.getAuthenticityList().contains("3")){
+
+                    }
+                    if(vo.getAuthenticityList().contains("4")){
+
+                    }
+                    if(vo.getAuthenticityList().contains("5")){
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对设定值域的元数据项值域符合度检测", 0, "无", 0));
                     }
+                    if(vo.getAuthenticityList().contains("6")){
+
+                    }
+                    if(vo.getAuthenticityList().contains("7")){
+
+                    }
+                    if(vo.getAuthenticityList().contains("8")){
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对元数据项数据重复性检测", 0, "无", 0));
+
+                    }
+                    if(vo.getAuthenticityList().contains("9")){
+
+                    }
+                    if(vo.getAuthenticityList().contains("10")){
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对信息包一致性检测", 0, "无", 0));
+                    }
+                    if(vo.getAuthenticityList().contains("11")){
+
+                    }
+                    if(vo.getAuthenticityList().contains("12")){
+
+                    }
+                    report.setReportDetailStatus(1);
+                    this.updateById(report);
+                }
+                //完整性
+                if (StringUtils.isNotBlank(vo.getIntegrality()) && "1".equals(vo.getIntegrality())) {
+                    Thread.sleep(5000L);
+                    if(vo.getAuthenticityList().contains("1")){
+
+                    }
+                    if(vo.getAuthenticityList().contains("2")){
+
+                    }
+                    if(vo.getAuthenticityList().contains("3")){
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_INTEGRALITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对元数据项完整性检测", 0, "无", 0));
+                    }
+                    if(vo.getAuthenticityList().contains("4")){
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_INTEGRALITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对元数据必填项检测", 0, "无", 0));
+                    }
+                    if(vo.getAuthenticityList().contains("5")){
+
+                    }
+                    if(vo.getAuthenticityList().contains("6")){
+
+                    }
+                    if(vo.getAuthenticityList().contains("7")){
+
+                    }
+                    if(vo.getAuthenticityList().contains("8")){
+
+                    }
+                    report.setReportDetailStatus(2);
+                    this.updateById(report);
+                }
+                //可用性
+                if (StringUtils.isNotBlank(vo.getUsability()) && "1".equals(vo.getUsability())) {
+                    Thread.sleep(5000L);
+                    if(vo.getAuthenticityList().contains("1")){
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对电子文件格式检测", 0, "无", 0));
+                    }
+                    //3-2 放在最开始
+                    if(vo.getAuthenticityList().contains("3")){
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对目标数据库中的元数据可访问性检测", 0, "无", 0));
+                    }
+                    if(vo.getAuthenticityList().contains("4")){
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对信息包中元数据可读性检测", 0, "无", 0));
+                    }
+                    if(vo.getAuthenticityList().contains("5")){
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对信息包中包含的内容数据合规性检测", 0, "无", 0));
+                    }
+                    if(vo.getAuthenticityList().contains("6")){
+
+                    }
+                    report.setReportDetailStatus(3);
+                    this.updateById(report);
+                }
+                //安全性
+                if (StringUtils.isNotBlank(vo.getSecurity()) && "1".equals(vo.getSecurity())) {
+                    if(vo.getAuthenticityList().contains("1")){
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_SECURITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对病毒感染检测", 0, "无", 0));
+                    }
+                    if(vo.getAuthenticityList().contains("2")){
+
+                    }
+                    if(vo.getAuthenticityList().contains("3")){
+                        detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_SECURITY,
+                                ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对系统环境中是否安装杀毒软件检测", 0, "无", 0));
+                    }
+                    if(vo.getAuthenticityList().contains("4")){
+
+                    }
+                    report.setReportDetailStatus(4);
+                    this.updateById(report);
                 }
             }
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对固化信息有效性检测", unqualifiedCount, unqualifiedCount == 0 ? "无" : "详见附件", unqualifiedCount == 0 ? 0 : 1));
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对电子文件内容一致性检测", 0, "无", 0));
-
-//            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
-//                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对元数据项数据长度检测", 0, "无", 0));
-//            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
-//                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对元数据项数据类型、格式检测", 0, "无", 0));
-            //要做
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对设定值域的元数据项值域符合度检测", 0, "无", 0));
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对元数据项数据重复性检测", 0, "无", 0));
-//            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
-//                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对元数据是否关联对应电子文件实体检测", 0, "无", 0));
-
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对信息包一致性检测", 0, "无", 0));
-//            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
-//                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对保存信息包封装规范性检测", 0, "无", 0));
-//            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_AUTHENTICITY,
-//                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对保存信息包一致性检测", 0, "无", 0));
-
-            report.setReportDetailStatus(1);
-            this.updateById(report);
-        }
-        if (StringUtils.isNotBlank(vo.getIntegrality()) && "1".equals(vo.getIntegrality())) {
-            Thread.sleep(5000L);
-            //完整性
-//            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_INTEGRALITY,
-//                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对电子文件实体数相符性检测", 0, "无", 0));
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_INTEGRALITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对元数据项完整性检测", 0, "无", 0));
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_INTEGRALITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对元数据必填项检测", 0, "无", 0));
-//            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_INTEGRALITY,
-//                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对连续性元数据项检测", 0, "无", 0));
-//            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_INTEGRALITY,
-//                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对信息包内容完整性检测", 0, "无", 0));
-//            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_INTEGRALITY,
-//                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对保存信息包元数据完整性检测", 0, "无", 0));
-//            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_INTEGRALITY,
-//                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对保存信息包内容数据完整性检测", 0, "无", 0));
-            report.setReportDetailStatus(2);
-            this.updateById(report);
-        }
-        //可用性
-        if (StringUtils.isNotBlank(vo.getUsability()) && "1".equals(vo.getUsability())) {
-            Thread.sleep(5000L);
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对电子文件格式检测", 0, "无", 0));
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对电子档案内容数据的可读性检测", 0, "无", 0));
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对目标数据库中的元数据可访问性检测", 0, "无", 0));
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对信息包中元数据可读性检测", 0, "无", 0));
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对信息包中包含的内容数据合规性检测", 0, "无", 0));
-//            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_USABILITY,
-//                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对保存信息包中元数据的可读性检测", 0, "无", 0));
-            report.setReportDetailStatus(3);
-            this.updateById(report);
-        }
-        //安全性
-        if (StringUtils.isNotBlank(vo.getSecurity()) && "1".equals(vo.getSecurity())) {
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_SECURITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对系统环境中是否安装杀毒软件检测", 0, "无", 0));
-            detailService.save(new ArchiveExaminingReportDetail(vo.getProjectId(), id, ArchiveConstant.ARCHIVE_EXAMINING_SECURITY,
-                    ArchiveConstant.ARCHIVE_EXAMINING_STANDARD + "对病毒感染检测", 0, "无", 0));
-            report.setReportDetailStatus(4);
-            this.updateById(report);
         }
         Thread.sleep(3000L);
         //生成报告,生成PDF
@@ -410,4 +526,25 @@ public class ArchiveExaminingReportImpl extends BaseServiceImpl<ArchiveExamining
         }
         return pdfPCell;
     }
+
+    public static boolean validateWithHead(String fileUrl) {
+        try (CloseableHttpClient client = HttpClients.createDefault()) {
+            HttpHead request = new HttpHead(fileUrl);
+
+            // 设置超时配置
+            RequestConfig config = RequestConfig.custom()
+                    .setConnectTimeout(5000)
+                    .setSocketTimeout(5000)
+                    .build();
+            request.setConfig(config);
+
+            try (var response = client.execute(request)) {
+                int statusCode = response.getStatusLine().getStatusCode();
+                return statusCode >= 200 && statusCode < 300;
+            }
+        } catch (Exception e) {
+            System.out.println("验证失败: " + e.getMessage());
+            return false;
+        }
+    }
 }

+ 303 - 0
blade-service/blade-archive/src/main/java/org/springblade/archive/utils/RemoteFileMD5Calculator.java

@@ -0,0 +1,303 @@
+package org.springblade.archive.utils;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class RemoteFileMD5Calculator {
+
+    private static final int BUFFER_SIZE = 64 * 1024; // 64KB
+    private static final int CONNECT_TIMEOUT = 10000; // 10秒
+    private static final int READ_TIMEOUT = 30000; // 30秒
+
+    /**
+     * 下载远程文件并计算MD5
+     */
+    public static MD5Result calculateRemoteFileMD5(String fileUrl) {
+        return calculateRemoteFileMD5(fileUrl, null);
+    }
+
+    public static MD5Result calculateRemoteFileMD5(String fileUrl, ProgressListener progressListener) {
+        HttpURLConnection connection = null;
+        InputStream inputStream = null;
+
+        try {
+            URL url = new URL(fileUrl);
+            connection = (HttpURLConnection) url.openConnection();
+            connection.setRequestMethod("GET");
+            connection.setConnectTimeout(CONNECT_TIMEOUT);
+            connection.setReadTimeout(READ_TIMEOUT);
+
+            // 设置请求头
+            connection.setRequestProperty("User-Agent",
+                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
+
+            int responseCode = connection.getResponseCode();
+            if (responseCode != HttpURLConnection.HTTP_OK) {
+                return new MD5Result(null, false, "HTTP错误: " + responseCode + " - " + connection.getResponseMessage(),0);
+            }
+
+            long contentLength = connection.getContentLengthLong();
+            String contentType = connection.getContentType();
+
+            System.out.println("开始下载文件: " + fileUrl);
+            System.out.println("文件大小: " + formatFileSize(contentLength));
+            System.out.println("Content-Type: " + contentType);
+
+            inputStream = connection.getInputStream();
+            MessageDigest md = MessageDigest.getInstance("MD5");
+
+            byte[] buffer = new byte[BUFFER_SIZE];
+            int bytesRead;
+            long totalBytesRead = 0;
+            long lastProgressUpdate = 0;
+
+            if (progressListener != null) {
+                progressListener.onStart(contentLength);
+            }
+
+            while ((bytesRead = inputStream.read(buffer)) != -1) {
+                md.update(buffer, 0, bytesRead);
+                totalBytesRead += bytesRead;
+
+                // 更新进度
+                if (progressListener != null) {
+                    long currentTime = System.currentTimeMillis();
+                    if (totalBytesRead - lastProgressUpdate >= 1024 * 1024 || // 每1MB更新一次
+                            totalBytesRead == contentLength) {
+
+                        double progress = contentLength > 0 ?
+                                (double) totalBytesRead / contentLength * 100 : 0;
+                        long elapsedTime = currentTime - progressListener.getStartTime();
+                        double speed = elapsedTime > 0 ?
+                                (double) totalBytesRead / elapsedTime * 1000 : 0;
+
+                        progressListener.onProgress(totalBytesRead, contentLength, progress, speed);
+                        lastProgressUpdate = totalBytesRead;
+                    }
+                }
+            }
+
+            byte[] digest = md.digest();
+            String md5Hash = bytesToHex(digest);
+
+            if (progressListener != null) {
+                progressListener.onComplete(md5Hash, totalBytesRead);
+            }
+
+            return new MD5Result(md5Hash, true, "下载并计算成功", contentLength);
+
+        } catch (Exception e) {
+            return new MD5Result(null, false, "错误: " + e.getMessage(), 0);
+        } finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                } catch (IOException e) {
+                    System.err.println("关闭输入流时出错: " + e.getMessage());
+                }
+            }
+            if (connection != null) {
+                connection.disconnect();
+            }
+        }
+    }
+
+    /**
+     * 获取远程文件的MD5(如果服务器提供ETag或Content-MD5头部)
+     */
+    public static MD5Result getRemoteFileMD5FromHeaders(String fileUrl) {
+        HttpURLConnection connection = null;
+
+        try {
+            URL url = new URL(fileUrl);
+            connection = (HttpURLConnection) url.openConnection();
+            connection.setRequestMethod("HEAD"); // 只请求头部信息
+            connection.setConnectTimeout(CONNECT_TIMEOUT);
+            connection.setReadTimeout(READ_TIMEOUT);
+
+            connection.setRequestProperty("User-Agent",
+                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
+
+            int responseCode = connection.getResponseCode();
+            if (responseCode != HttpURLConnection.HTTP_OK) {
+                return new MD5Result(null, false,
+                        "HTTP错误: " + responseCode + " - " + connection.getResponseMessage());
+            }
+
+            // 检查常见的MD5相关头部
+            String etag = connection.getHeaderField("ETag");
+            String contentMD5 = connection.getHeaderField("Content-MD5");
+            String contentLength = connection.getHeaderField("Content-Length");
+
+            System.out.println("ETag: " + etag);
+            System.out.println("Content-MD5: " + contentMD5);
+            System.out.println("Content-Length: " + contentLength);
+
+            // 尝试从ETag提取MD5(常见格式:"md5-hash" 或 "md5-hash-extra")
+            if (etag != null) {
+                // 移除引号
+                etag = etag.replace("\"", "");
+
+                // 检查是否是MD5格式(32位十六进制)
+                if (etag.matches("[a-fA-F0-9]{32}")) {
+                    return new MD5Result(etag.toLowerCase(), true,
+                            "从ETag头部获取", Long.parseLong(contentLength != null ? contentLength : "0"));
+                }
+
+                // 检查是否包含MD5(如:"5d41402abc4b2a76b9719d911017c592-gzip")
+                if (etag.length() >= 32) {
+                    String possibleMD5 = etag.substring(0, 32);
+                    if (possibleMD5.matches("[a-fA-F0-9]{32}")) {
+                        return new MD5Result(possibleMD5.toLowerCase(), true,
+                                "从ETag提取", Long.parseLong(contentLength != null ? contentLength : "0"));
+                    }
+                }
+            }
+
+            // 直接使用Content-MD5(需要Base64解码)
+            if (contentMD5 != null) {
+                try {
+                    byte[] md5Bytes = java.util.Base64.getDecoder().decode(contentMD5);
+                    String md5Hash = bytesToHex(md5Bytes);
+                    return new MD5Result(md5Hash, true,
+                            "从Content-MD5头部获取", Long.parseLong(contentLength != null ? contentLength : "0"));
+                } catch (IllegalArgumentException e) {
+                    System.out.println("Content-MD5 Base64解码失败: " + e.getMessage());
+                }
+            }
+
+            return new MD5Result(null, false,
+                    "服务器未提供MD5信息", Long.parseLong(contentLength != null ? contentLength : "0"));
+
+        } catch (Exception e) {
+            return new MD5Result(null, false, "错误: " + e.getMessage(), 0);
+        } finally {
+            if (connection != null) {
+                connection.disconnect();
+            }
+        }
+    }
+
+    /**
+     * 字节数组转十六进制字符串
+     */
+    private static String bytesToHex(byte[] bytes) {
+        StringBuilder hexString = new StringBuilder(bytes.length * 2);
+        for (byte b : bytes) {
+            String hex = Integer.toHexString(0xff & b);
+            if (hex.length() == 1) {
+                hexString.append('0');
+            }
+            hexString.append(hex);
+        }
+        return hexString.toString();
+    }
+
+    /**
+     * 格式化文件大小
+     */
+    private static String formatFileSize(long size) {
+        if (size < 1024) return size + " B";
+        if (size < 1024 * 1024) return String.format("%.2f KB", size / 1024.0);
+        if (size < 1024 * 1024 * 1024) return String.format("%.2f MB", size / (1024.0 * 1024.0));
+        return String.format("%.2f GB", size / (1024.0 * 1024.0 * 1024.0));
+    }
+
+    /**
+     * 进度监听器接口
+     */
+    public interface ProgressListener {
+        void onStart(long totalSize);
+        void onProgress(long bytesRead, long totalSize, double progress, double speedBytesPerSec);
+        void onComplete(String md5Hash, long totalBytesProcessed);
+        long getStartTime();
+    }
+
+    /**
+     * 默认进度监听器
+     */
+    public static class DefaultProgressListener implements ProgressListener {
+        private long startTime;
+
+        @Override
+        public void onStart(long totalSize) {
+            this.startTime = System.currentTimeMillis();
+            System.out.println("开始下载,文件大小: " + formatFileSize(totalSize));
+        }
+
+        @Override
+        public void onProgress(long bytesRead, long totalSize, double progress, double speedBytesPerSec) {
+            String progressBar = createProgressBar(progress, 20);
+            System.out.printf("\r%s [%s] %.2f%% | 速度: %s/s",
+                    progressBar,
+                    formatFileSize(bytesRead) + "/" + formatFileSize(totalSize),
+                    progress,
+                    formatFileSize((long) speedBytesPerSec));
+        }
+
+        @Override
+        public void onComplete(String md5Hash, long totalBytesProcessed) {
+            long endTime = System.currentTimeMillis();
+            long elapsedTime = endTime - startTime;
+            System.out.printf("\n下载完成! 耗时: %.2f秒 | MD5: %s\n",
+                    elapsedTime / 1000.0, md5Hash);
+        }
+
+        @Override
+        public long getStartTime() {
+            return startTime;
+        }
+
+        private String createProgressBar(double progress, int length) {
+            int filledLength = (int) (progress / 100 * length);
+            StringBuilder bar = new StringBuilder();
+            for (int i = 0; i < length; i++) {
+                if (i < filledLength) {
+                    bar.append("=");
+                } else if (i == filledLength) {
+                    bar.append(">");
+                } else {
+                    bar.append(" ");
+                }
+            }
+            return bar.toString();
+        }
+    }
+
+    /**
+     * MD5计算结果封装
+     */
+    public static class MD5Result {
+        public final String md5Hash;
+        public final boolean success;
+        public final String message;
+        public final long fileSize;
+
+        public MD5Result(String md5Hash, boolean success, String message, long fileSize) {
+            this.md5Hash = md5Hash;
+            this.success = success;
+            this.message = message;
+            this.fileSize = fileSize;
+        }
+        public MD5Result(String md5Hash, boolean success, String message) {
+            this.md5Hash = md5Hash;
+            this.success = success;
+            this.message = message;
+            this.fileSize = 0;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("=== 远程文件MD5计算结果 ===\n");
+            sb.append("文件大小: ").append(formatFileSize(fileSize)).append("\n");
+            sb.append("计算状态: ").append(success ? "成功" : "失败").append("\n");
+            sb.append("MD5值: ").append(md5Hash != null ? md5Hash : "N/A").append("\n");
+            sb.append("信息: ").append(message);
+            return sb.toString();
+        }
+    }
+}