|
@@ -0,0 +1,520 @@
|
|
|
+package org.springblade.archive.service.impl;
|
|
|
+
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import io.swagger.annotations.ApiModelProperty;
|
|
|
+import lombok.AllArgsConstructor;
|
|
|
+import org.springblade.archive.entity.ArchivesAuto;
|
|
|
+import org.springblade.archive.entity.ScanFile;
|
|
|
+import org.springblade.archive.entity.ScanFolder;
|
|
|
+import org.springblade.archive.mapper.ScanFileMapper;
|
|
|
+import org.springblade.archive.mapper.ScanFolderMapper;
|
|
|
+import org.springblade.archive.service.ScanFileService;
|
|
|
+import org.springblade.archive.utils.FileUtils;
|
|
|
+import org.springblade.archive.vo.ScanFolderVO;
|
|
|
+import org.springblade.business.entity.ArchiveFile;
|
|
|
+import org.springblade.business.feign.ArchiveFileClient;
|
|
|
+import org.springblade.common.utils.SnowFlakeUtil;
|
|
|
+import org.springblade.core.mp.support.Query;
|
|
|
+import org.springblade.core.oss.model.BladeFile;
|
|
|
+import org.springblade.core.tool.api.R;
|
|
|
+import org.springblade.core.tool.utils.Func;
|
|
|
+import org.springblade.core.tool.utils.StringUtil;
|
|
|
+import org.springblade.manager.entity.ArchiveTreeContract;
|
|
|
+import org.springblade.manager.feign.ArchiveTreeContractClient;
|
|
|
+import org.springblade.resource.feign.NewIOSSClient;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
+import org.springframework.jdbc.core.JdbcTemplate;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.net.URL;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.StandardCopyOption;
|
|
|
+import java.nio.file.attribute.BasicFileAttributes;
|
|
|
+import java.security.DigestInputStream;
|
|
|
+import java.security.MessageDigest;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+
|
|
|
+@Service
|
|
|
+@AllArgsConstructor
|
|
|
+public class ScanFileServiceImpl extends ServiceImpl<ScanFileMapper, ScanFile> implements ScanFileService {
|
|
|
+// //文件根目录
|
|
|
+// private static final String ROOT_PREFIX = "D:" + File.separator + "ScanPDF";
|
|
|
+// //备份文件根目录
|
|
|
+// private static final String ROOT_PREFIX_back = "D:" + File.separator + "ScanBackPDF";
|
|
|
+ //文件根目录
|
|
|
+ private static final String ROOT_PREFIX = "/mnt/sdc/ScanPDF";
|
|
|
+ //备份文件根目录
|
|
|
+ private static final String ROOT_PREFIX_back = "/mnt/sdc/ScanBackPDF";
|
|
|
+
|
|
|
+ private final ScanFolderMapper scanFolderMapper;
|
|
|
+ private final ScanFileMapper scanFileMapper;
|
|
|
+ private final NewIOSSClient newIOSSClient;
|
|
|
+ private final ArchiveTreeContractClient archiveTreeContractClient;
|
|
|
+ private final JdbcTemplate jdbcTemplate;
|
|
|
+ private final ArchiveFileClient archiveFileClient;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void scanAndSave(Long contractId, Long projectId) {
|
|
|
+ //扫描文件夹
|
|
|
+ scanAndSaveFolder(contractId, projectId);
|
|
|
+ //扫描文件
|
|
|
+ scanAndSaveFiles(contractId,projectId);
|
|
|
+ //整理编号,序号
|
|
|
+ sortNumber(contractId, projectId);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<ScanFolderVO> getScanFolder(Long contractId, Long projectId) {
|
|
|
+ List<ScanFolder> list = scanFileMapper.getScanFolder(contractId,projectId);
|
|
|
+ // 将ScanFolder转换为ScanFolderVO
|
|
|
+ List<ScanFolderVO> voList = list.stream().map(scanFolder -> {
|
|
|
+ ScanFolderVO vo = new ScanFolderVO();
|
|
|
+ // 复制属性
|
|
|
+ BeanUtils.copyProperties(scanFolder, vo);
|
|
|
+ // 初始化子节点列表
|
|
|
+ vo.setChilds(new ArrayList<>());
|
|
|
+ // 默认为没有子节点,后续会重新判断
|
|
|
+ vo.setHasChildren(false);
|
|
|
+ return vo;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+
|
|
|
+ // 构建父子关系
|
|
|
+ Map<Long, ScanFolderVO> voMap = voList.stream()
|
|
|
+ .collect(Collectors.toMap(ScanFolderVO::getId, v -> v));
|
|
|
+
|
|
|
+ List<ScanFolderVO> result = new ArrayList<>();
|
|
|
+
|
|
|
+ for (ScanFolderVO vo : voList) {
|
|
|
+ Long parentId = vo.getParentId();
|
|
|
+ if (parentId == null || parentId == 0) {
|
|
|
+ // 没有父节点的作为根节点
|
|
|
+ result.add(vo);
|
|
|
+ } else {
|
|
|
+ // 有父节点的添加到对应父节点的子列表中
|
|
|
+ ScanFolderVO parent = voMap.get(parentId);
|
|
|
+ if (parent != null) {
|
|
|
+ parent.getChilds().add(vo);
|
|
|
+ parent.setHasChildren(true); // 标记父节点有子节点
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public IPage<ScanFile> getScanFile(Long contractId, Long projectId, Long folderId, Query query,Integer move) {
|
|
|
+ IPage<ScanFile> page = new Page<>(query.getCurrent(), query.getSize());
|
|
|
+ page=baseMapper.getScanFile(page,contractId,projectId,folderId,move);
|
|
|
+ return page;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String deleteScanFile(String ids) {
|
|
|
+ List<Long> longList = Func.toLongList(ids);
|
|
|
+ List<ScanFile> scanFiles = baseMapper.selectList(new LambdaQueryWrapper<>(ScanFile.class).in(ScanFile::getId, longList));
|
|
|
+ List<String> fileNames = scanFiles.stream().filter(o-> !StringUtil.isBlank(o.getFileName())).map(o -> o.getFileName()).collect(Collectors.toList());
|
|
|
+ baseMapper.removeScan(longList);
|
|
|
+ newIOSSClient.removeFiles(fileNames);
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Boolean autoRecognize(String ids) {
|
|
|
+ List<Long> longList = Func.toLongList(ids);
|
|
|
+ List<ScanFile> scanFiles = baseMapper.selectList(new LambdaQueryWrapper<>(ScanFile.class).in(ScanFile::getId, longList));
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean moveScanFile(List<Long> ids, Long nodeId) {
|
|
|
+ try {
|
|
|
+ List<ScanFile> scanFiles = baseMapper.selectList(new LambdaQueryWrapper<>(ScanFile.class).in(ScanFile::getId, ids));
|
|
|
+ ArchiveTreeContract contract = archiveTreeContractClient.getArchiveTreeContractById(nodeId);
|
|
|
+ String sql="select IFNULL(max(sort),0) from u_archive_file where project_id="+contract.getProjectId()+" and contract_id="+contract.getContractId()+" and is_deleted=0";
|
|
|
+ Integer sort = jdbcTemplate.queryForObject(sql, Integer.class);
|
|
|
+ List<ArchiveFile>list=new ArrayList<>();
|
|
|
+ if(contract!=null){
|
|
|
+ for (ScanFile file : scanFiles) {
|
|
|
+ ArchiveFile archiveFile = new ArchiveFile();
|
|
|
+ archiveFile.setId(SnowFlakeUtil.getId());
|
|
|
+ archiveFile.setProjectId(contract.getProjectId()+"");
|
|
|
+ archiveFile.setContractId(contract.getContractId()+"");
|
|
|
+ archiveFile.setNodeId(nodeId+"");
|
|
|
+ archiveFile.setFileNumber(file.getFileNum());
|
|
|
+ archiveFile.setFileName(file.getFileName());
|
|
|
+ archiveFile.setFileTime(file.getFileDate());
|
|
|
+ archiveFile.setFileUrl(file.getOssUrl());
|
|
|
+ archiveFile.setPdfFileUrl(file.getOssUrl());
|
|
|
+ archiveFile.setFilePage(file.getFileSize()!=null?Integer.parseInt(file.getFileSize()):0);
|
|
|
+ archiveFile.setIsApproval(0);
|
|
|
+ archiveFile.setIsNeedCertification(0);
|
|
|
+ archiveFile.setIsCertification(0);
|
|
|
+ archiveFile.setDutyUser(file.getResponsible());
|
|
|
+ archiveFile.setIsArchive(0);
|
|
|
+ archiveFile.setSourceType(2);
|
|
|
+ archiveFile.setIsElement(0);
|
|
|
+ archiveFile.setClassify(contract.getClassify());
|
|
|
+ archiveFile.setNodeTreeStructure(contract.getTreeStructure());
|
|
|
+ archiveFile.setSort(sort++);
|
|
|
+ list.add(archiveFile);
|
|
|
+ }
|
|
|
+ archiveFileClient.saveBatchArchiveFile(list);
|
|
|
+ for (ScanFile file : scanFiles) {
|
|
|
+ file.setIsMove(1);
|
|
|
+ }
|
|
|
+ this.updateBatchById(scanFiles);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }catch (Exception e){
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 入口方法:扫描并入库指定contractId的所有文件夹
|
|
|
+ * @param contractId 传入的合同ID(对应D:\PDF下的文件夹名)
|
|
|
+ * @param projectId 传入的项目ID
|
|
|
+ */
|
|
|
+ public R scanAndSaveFolder(Long contractId, Long projectId) {
|
|
|
+ // 1. 构建合同对应的根文件夹路径(D:\PDF\${contractId})
|
|
|
+ String contractFolderPath = ROOT_PREFIX + File.separator + contractId;
|
|
|
+ System.out.println("contractFolderPath=" + contractFolderPath);
|
|
|
+ File contractFolder = new File(contractFolderPath);
|
|
|
+
|
|
|
+ // 校验根文件夹是否存在且为目录
|
|
|
+ if (!contractFolder.exists() || !contractFolder.isDirectory()) {
|
|
|
+ return R.fail("错误:根文件夹不存在或非法,路径=" + contractFolderPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 扫描一级文件夹(parent_id=0)并入库,同时递归子文件夹
|
|
|
+ File[] firstLevelFolders = contractFolder.listFiles(File::isDirectory);
|
|
|
+ if (firstLevelFolders == null || firstLevelFolders.length == 0) {
|
|
|
+ return R.fail("提示:合同ID=" + contractId + "的根文件夹下无任何子文件夹");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 遍历一级文件夹,逐个入库并递归子目录
|
|
|
+ for (File firstLevelFolder : firstLevelFolders) {
|
|
|
+ String folderName = firstLevelFolder.getName();
|
|
|
+ Long folderId = scanFolderMapper.getId(folderName,contractId,projectId);
|
|
|
+ if(folderId==null){
|
|
|
+ folderId=SnowFlakeUtil.getId(); // 生成随机ID
|
|
|
+ }
|
|
|
+ String filePath = firstLevelFolder.getAbsolutePath();
|
|
|
+ // 创建一级目录的ScanFolder对象(parent_id=0)
|
|
|
+ ScanFolder firstLevelScanFolder = new ScanFolder(
|
|
|
+ folderId,
|
|
|
+ 0L, // 一级目录父ID固定为0
|
|
|
+ projectId,
|
|
|
+ contractId,
|
|
|
+ folderName,
|
|
|
+ filePath,
|
|
|
+ 0
|
|
|
+ );
|
|
|
+ // 入库一级目录
|
|
|
+ checkInsertScanFolder(firstLevelScanFolder);
|
|
|
+ // 递归扫描当前一级目录下的所有子文件夹(子目录的父ID=当前一级目录ID)
|
|
|
+ recursiveScanSubFolders(firstLevelFolder, folderId, projectId, contractId);
|
|
|
+
|
|
|
+ }
|
|
|
+ return R.success("扫描并入库成功");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 递归扫描子文件夹并入库
|
|
|
+ * @param parentFolder 父文件夹对象(当前要扫描子目录的文件夹)
|
|
|
+ * @param parentFolderId 父文件夹在数据库中的ID(子目录的parent_id)
|
|
|
+ * @param projectId 项目ID(透传)
|
|
|
+ * @param contractId 合同ID(透传)
|
|
|
+ */
|
|
|
+ private void recursiveScanSubFolders(File parentFolder, Long parentFolderId, Long projectId, Long contractId) {
|
|
|
+ // 获取父文件夹下的所有子文件夹
|
|
|
+ File[] subFolders = parentFolder.listFiles(File::isDirectory);
|
|
|
+ if (subFolders == null || subFolders.length == 0) {
|
|
|
+ System.out.println("递归终止:父ID=" + parentFolderId + "(名称=" + parentFolder.getName() + ")下无子文件夹");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 遍历每个子文件夹,入库并继续递归其下的子目录
|
|
|
+ for (File subFolder : subFolders) {
|
|
|
+ String subFolderName = subFolder.getName();
|
|
|
+ Long subFolderId = scanFolderMapper.getId(subFolderName,contractId,projectId);
|
|
|
+ if(subFolderId==null){
|
|
|
+ subFolderId=SnowFlakeUtil.getId(); // 生成随机ID
|
|
|
+ }
|
|
|
+ String filePath = subFolder.getAbsolutePath();
|
|
|
+
|
|
|
+ // 创建子目录的ScanFolder对象(parent_id=父文件夹ID)
|
|
|
+ ScanFolder subScanFolder = new ScanFolder(
|
|
|
+ subFolderId,
|
|
|
+ parentFolderId, // 关联父目录ID
|
|
|
+ projectId,
|
|
|
+ contractId,
|
|
|
+ subFolderName,
|
|
|
+ filePath,
|
|
|
+ 0
|
|
|
+ );
|
|
|
+ // 入库子目录
|
|
|
+ checkInsertScanFolder(subScanFolder);
|
|
|
+ // 递归扫描当前子目录下的子文件夹
|
|
|
+ recursiveScanSubFolders(subFolder, subFolderId, projectId, contractId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查文件夹是否存在,不存在则新增
|
|
|
+ * @param scanFolder
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public boolean checkInsertScanFolder(ScanFolder scanFolder) {
|
|
|
+ int result = scanFolderMapper.exists(scanFolder.getProjectId(), scanFolder.getContractId(), scanFolder.getFolderName());
|
|
|
+ if(result>0){
|
|
|
+ return false;
|
|
|
+ }else {
|
|
|
+ scanFolderMapper.insert(scanFolder);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 扫描文件并入库
|
|
|
+ * @param contractId
|
|
|
+ * @param projectId
|
|
|
+ */
|
|
|
+ public R scanAndSaveFiles(Long contractId, Long projectId) {
|
|
|
+ // 1. 构建合同对应的根文件夹路径(D:\PDF\${contractId})
|
|
|
+ String contractFolderPath = ROOT_PREFIX + File.separator + contractId;
|
|
|
+ System.out.println("contractFolderPath=" + contractFolderPath);
|
|
|
+ File contractFolder = new File(contractFolderPath);
|
|
|
+
|
|
|
+ // 校验根文件夹是否存在且为目录
|
|
|
+ if (!contractFolder.exists() || !contractFolder.isDirectory()) {
|
|
|
+ return R.fail("错误:根文件夹不存在或非法,路径=" + contractFolderPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.println("开始扫描合同ID=" + contractId + "下的所有文件...");
|
|
|
+ // 递归扫描所有文件
|
|
|
+ recursiveScanFiles(contractFolder, projectId, contractId);
|
|
|
+ System.out.println("合同ID=" + contractId + "的文件扫描入库完成");
|
|
|
+ return R.success("扫描并入库完成");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void sortNumber(Long contractId, Long projectId) {
|
|
|
+ List<ScanFile> scanFiles = scanFileMapper.selectList(new LambdaQueryWrapper<ScanFile>().eq(ScanFile::getContractId, contractId).eq(ScanFile::getProjectId, projectId).isNull(ScanFile::getSort).isNull(ScanFile::getDigitalNum).orderByAsc(ScanFile::getCreatTime));
|
|
|
+ Integer maxDigitalNum=scanFileMapper.selectMaxDigitalNum(contractId,projectId);
|
|
|
+ if(maxDigitalNum==null||maxDigitalNum<1){
|
|
|
+ maxDigitalNum=0;
|
|
|
+ }
|
|
|
+ Map<Long, List<ScanFile>> scanFilesMap = scanFiles.stream()
|
|
|
+ .collect(Collectors.groupingBy(ScanFile::getFolderId));
|
|
|
+ for (Map.Entry<Long, List<ScanFile>> entry : scanFilesMap.entrySet()) {
|
|
|
+ Integer MaxSort=scanFileMapper.selectMaxSort(contractId,projectId,entry.getKey());
|
|
|
+ if(MaxSort==null||MaxSort<1){
|
|
|
+ MaxSort=0;
|
|
|
+ }
|
|
|
+ List<ScanFile> list = entry.getValue();
|
|
|
+ for (ScanFile scanFile : list) {
|
|
|
+ scanFile.setSort(++MaxSort);
|
|
|
+ scanFile.setDigitalNum(++maxDigitalNum);
|
|
|
+ scanFileMapper.updateById(scanFile);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 递归扫描文件夹中的所有文件并入库
|
|
|
+ * @param currentFolder 当前扫描的文件夹
|
|
|
+ * @param projectId 项目ID
|
|
|
+ * @param contractId 合同ID
|
|
|
+ */
|
|
|
+ private void recursiveScanFiles(File currentFolder, Long projectId, Long contractId) {
|
|
|
+ // 1. 先处理当前文件夹中的文件
|
|
|
+ File[] files = currentFolder.listFiles(File::isFile);
|
|
|
+ if (files != null && files.length > 0) {
|
|
|
+ for (File file : files) {
|
|
|
+ processFile(file, currentFolder, projectId, contractId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 递归处理子文件夹
|
|
|
+ File[] subFolders = currentFolder.listFiles(File::isDirectory);
|
|
|
+ if (subFolders != null && subFolders.length > 0) {
|
|
|
+ for (File subFolder : subFolders) {
|
|
|
+ recursiveScanFiles(subFolder, projectId, contractId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理单个文件:获取信息并入库
|
|
|
+ */
|
|
|
+ private void processFile(File file, File parentFolder, Long projectId, Long contractId) {
|
|
|
+ String fileMD5 = calculateFileMD5(file);
|
|
|
+ try {
|
|
|
+ // 获取文件创建时间
|
|
|
+ BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
|
|
+ Date date = new Date(attr.creationTime().toMillis());
|
|
|
+ SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
+ String createTime = sdf1.format(date); // 2023-12-25 14:30:45
|
|
|
+ // 获取文件信息
|
|
|
+ String fileName = file.getName();
|
|
|
+ String filePath = file.getAbsolutePath();
|
|
|
+ String folderName = parentFolder.getName();
|
|
|
+ // 查询对应的folder_id
|
|
|
+ Long folderId = scanFolderMapper.getId(folderName,contractId,projectId);
|
|
|
+ if (folderId == null) {
|
|
|
+ System.err.println("警告:未找到对应的文件夹记录,跳过文件:" + filePath +
|
|
|
+ " (folderName=" + folderName + ")");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 检查文件是否已存在(根据project_id, contract_id, file_path判断)
|
|
|
+ if (fileExists(projectId, contractId, folderName)) {
|
|
|
+ System.out.println("文件已存在,跳过:" + filePath);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ BladeFile bladeFile = newIOSSClient.uploadFile(fileName, filePath);
|
|
|
+ if(bladeFile==null){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String oSSFileMD5 = calculateOSSFileMD5(bladeFile.getLink());
|
|
|
+ if (fileMD5 != null && !fileMD5.equals(oSSFileMD5)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String pdfNum = FileUtils.getPdfNum(bladeFile.getLink());
|
|
|
+ // 生成随机ID
|
|
|
+ Long fileId = SnowFlakeUtil.getId();
|
|
|
+ // 创建文件实体
|
|
|
+ ScanFile scanFile = new ScanFile(
|
|
|
+ fileId,
|
|
|
+ projectId,
|
|
|
+ contractId,
|
|
|
+ folderId,
|
|
|
+ null,//序号
|
|
|
+ null,//数字编号
|
|
|
+ null,//文件编号
|
|
|
+ fileName,
|
|
|
+ pdfNum,//文件页数
|
|
|
+ null,//文件日期
|
|
|
+ createTime,
|
|
|
+ filePath,
|
|
|
+ bladeFile.getLink(),//OSS路径
|
|
|
+ null,//负责人
|
|
|
+ 0,
|
|
|
+ 0
|
|
|
+ );
|
|
|
+ // 入库
|
|
|
+ if (scanFileMapper.insert(scanFile)>0) {
|
|
|
+ System.out.println("文件入库成功:" + filePath);
|
|
|
+ try {
|
|
|
+ // 构建备份文件路径,保持原有的文件夹结构
|
|
|
+ if (filePath.startsWith(ROOT_PREFIX)) {
|
|
|
+ // 截取原始路径中除根目录外的部分
|
|
|
+ String relativePath = filePath.substring(ROOT_PREFIX.length());
|
|
|
+ System.out.println("relativePath: " + relativePath);
|
|
|
+ // 构建备份文件完整路径
|
|
|
+ String backupFilePath = ROOT_PREFIX_back + relativePath;
|
|
|
+ System.out.println("backupFilePath: " + backupFilePath);
|
|
|
+ File backupFile = new File(backupFilePath);
|
|
|
+ // 创建备份文件所在的目录
|
|
|
+ File backupDir = backupFile.getParentFile();
|
|
|
+ if (!backupDir.exists()) {
|
|
|
+ boolean dirCreated = backupDir.mkdirs();
|
|
|
+ if (!dirCreated) {
|
|
|
+ throw new IOException("无法创建备份目录: " + backupDir.getAbsolutePath());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 复制文件到备份目录
|
|
|
+ Files.copy(file.toPath(), backupFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
|
+ String fileMD5New = calculateFileMD5(backupFile);
|
|
|
+ if (fileMD5New != null && fileMD5New.equals(fileMD5)) {
|
|
|
+ // 备份成功后删除源文件
|
|
|
+ file.delete();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ System.err.println("文件备份失败:" + filePath + ",错误信息:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ System.err.println("处理文件时出错:" + file.getAbsolutePath() + ",错误信息:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private Boolean fileExists(Long projectId, Long contractId, String folderName){
|
|
|
+ Integer i = scanFileMapper.exists(projectId, contractId, folderName);
|
|
|
+ if(i==1){
|
|
|
+ return true;
|
|
|
+ }else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private String calculateFileMD5(File file) {
|
|
|
+ try {
|
|
|
+ MessageDigest md = MessageDigest.getInstance("MD5");
|
|
|
+ try (InputStream is = Files.newInputStream(file.toPath());
|
|
|
+ DigestInputStream dis = new DigestInputStream(is, md)) {
|
|
|
+ byte[] buffer = new byte[8192];
|
|
|
+ while (dis.read(buffer) != -1) {
|
|
|
+ // 读取文件内容以计算MD5
|
|
|
+ }
|
|
|
+ }
|
|
|
+ byte[] digest = md.digest();
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ for (byte b : digest) {
|
|
|
+ sb.append(String.format("%02x", b));
|
|
|
+ }
|
|
|
+ return sb.toString();
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("计算本地文件MD5失败:" + file.getAbsolutePath() + ",错误信息:" + e.getMessage());
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算OSS文件的MD5值
|
|
|
+ * @param ossUrl OSS文件路径
|
|
|
+ * @return MD5值,如果出错返回null
|
|
|
+ */
|
|
|
+ private String calculateOSSFileMD5(String ossUrl) {
|
|
|
+ try {
|
|
|
+ MessageDigest md = MessageDigest.getInstance("MD5");
|
|
|
+
|
|
|
+ // 使用URL下载OSS文件
|
|
|
+ URL url = new URL(ossUrl);
|
|
|
+ try (InputStream is = url.openStream();
|
|
|
+ DigestInputStream dis = new DigestInputStream(is, md)) {
|
|
|
+ byte[] buffer = new byte[8192];
|
|
|
+ while (dis.read(buffer) != -1) {
|
|
|
+ // 读取文件内容以计算MD5
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ byte[] digest = md.digest();
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ for (byte b : digest) {
|
|
|
+ sb.append(String.format("%02x", b));
|
|
|
+ }
|
|
|
+ return sb.toString();
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("计算OSS文件MD5失败:" + ossUrl + ",错误信息:" + e.getMessage());
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|