|
@@ -1,5 +1,6 @@
|
|
package org.springblade.archive.service.impl;
|
|
package org.springblade.archive.service.impl;
|
|
|
|
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
import lombok.AllArgsConstructor;
|
|
import lombok.AllArgsConstructor;
|
|
import org.springblade.archive.entity.ScanFile;
|
|
import org.springblade.archive.entity.ScanFile;
|
|
@@ -15,11 +16,18 @@ import org.springblade.resource.feign.NewIOSSClient;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
import java.io.File;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
|
|
+import java.io.InputStream;
|
|
|
|
+import java.net.URL;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.StandardCopyOption;
|
|
import java.nio.file.StandardCopyOption;
|
|
import java.nio.file.attribute.BasicFileAttributes;
|
|
import java.nio.file.attribute.BasicFileAttributes;
|
|
|
|
+import java.security.DigestInputStream;
|
|
|
|
+import java.security.MessageDigest;
|
|
import java.text.SimpleDateFormat;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.Date;
|
|
import java.util.Date;
|
|
|
|
+import java.util.List;
|
|
|
|
+import java.util.Map;
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
@Service
|
|
@Service
|
|
@@ -34,12 +42,24 @@ public class ScanFileServiceImpl extends ServiceImpl<ScanFileMapper, ScanFile>
|
|
private final ScanFileMapper scanFileMapper;
|
|
private final ScanFileMapper scanFileMapper;
|
|
private final NewIOSSClient newIOSSClient;
|
|
private final NewIOSSClient newIOSSClient;
|
|
|
|
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void scanAndSave(Long contractId, Long projectId) {
|
|
|
|
+ //扫描文件夹
|
|
|
|
+ scanAndSaveFolder(contractId, projectId);
|
|
|
|
+ //扫描文件
|
|
|
|
+ scanAndSaveFiles(contractId,projectId);
|
|
|
|
+ //整理编号,序号
|
|
|
|
+ sortNumber(contractId, projectId);
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 入口方法:扫描并入库指定contractId的所有文件夹
|
|
* 入口方法:扫描并入库指定contractId的所有文件夹
|
|
* @param contractId 传入的合同ID(对应D:\PDF下的文件夹名)
|
|
* @param contractId 传入的合同ID(对应D:\PDF下的文件夹名)
|
|
* @param projectId 传入的项目ID
|
|
* @param projectId 传入的项目ID
|
|
*/
|
|
*/
|
|
- public R scanAndSave(Long contractId, Long projectId) {
|
|
|
|
|
|
+ public R scanAndSaveFolder(Long contractId, Long projectId) {
|
|
// 1. 构建合同对应的根文件夹路径(D:\PDF\${contractId})
|
|
// 1. 构建合同对应的根文件夹路径(D:\PDF\${contractId})
|
|
String contractFolderPath = ROOT_PREFIX + File.separator + contractId;
|
|
String contractFolderPath = ROOT_PREFIX + File.separator + contractId;
|
|
File contractFolder = new File(contractFolderPath);
|
|
File contractFolder = new File(contractFolderPath);
|
|
@@ -161,6 +181,30 @@ public class ScanFileServiceImpl extends ServiceImpl<ScanFileMapper, ScanFile>
|
|
return R.success("扫描并入库完成");
|
|
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).orderByDesc(ScanFile::getFileDate));
|
|
|
|
+ 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 currentFolder 当前扫描的文件夹
|
|
@@ -189,6 +233,7 @@ public class ScanFileServiceImpl extends ServiceImpl<ScanFileMapper, ScanFile>
|
|
* 处理单个文件:获取信息并入库
|
|
* 处理单个文件:获取信息并入库
|
|
*/
|
|
*/
|
|
private void processFile(File file, File parentFolder, Long projectId, Long contractId) {
|
|
private void processFile(File file, File parentFolder, Long projectId, Long contractId) {
|
|
|
|
+ String fileMD5 = calculateFileMD5(file);
|
|
try {
|
|
try {
|
|
// 获取文件创建时间
|
|
// 获取文件创建时间
|
|
BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
|
BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
|
@@ -215,6 +260,10 @@ public class ScanFileServiceImpl extends ServiceImpl<ScanFileMapper, ScanFile>
|
|
if(bladeFile==null){
|
|
if(bladeFile==null){
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
+ String oSSFileMD5 = calculateOSSFileMD5(bladeFile.getLink());
|
|
|
|
+ if (fileMD5 != null && !fileMD5.equals(oSSFileMD5)) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
String pdfNum = FileUtils.getPdfNum(bladeFile.getLink());
|
|
String pdfNum = FileUtils.getPdfNum(bladeFile.getLink());
|
|
// 生成随机ID
|
|
// 生成随机ID
|
|
Long fileId = SnowFlakeUtil.getId();
|
|
Long fileId = SnowFlakeUtil.getId();
|
|
@@ -256,28 +305,20 @@ public class ScanFileServiceImpl extends ServiceImpl<ScanFileMapper, ScanFile>
|
|
}
|
|
}
|
|
// 复制文件到备份目录
|
|
// 复制文件到备份目录
|
|
Files.copy(file.toPath(), backupFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
Files.copy(file.toPath(), backupFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
- System.out.println("文件备份成功:" + backupFilePath);
|
|
|
|
- // 备份成功后删除源文件
|
|
|
|
- boolean deleted = file.delete();
|
|
|
|
- if (deleted) {
|
|
|
|
- System.out.println("源文件已删除:" + filePath);
|
|
|
|
- } else {
|
|
|
|
- System.err.println("警告:备份成功,但无法删除源文件:" + filePath);
|
|
|
|
|
|
+ String fileMD5New = calculateFileMD5(backupFile);
|
|
|
|
+ if (fileMD5New != null && fileMD5New.equals(fileMD5)) {
|
|
|
|
+ // 备份成功后删除源文件
|
|
|
|
+ file.delete();
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
- System.err.println("警告:文件路径不在预期的根目录下,无法备份:" + filePath);
|
|
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
} catch (IOException e) {
|
|
System.err.println("文件备份失败:" + filePath + ",错误信息:" + e.getMessage());
|
|
System.err.println("文件备份失败:" + filePath + ",错误信息:" + e.getMessage());
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
- System.err.println("文件入库失败:" + filePath);
|
|
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
} catch (IOException e) {
|
|
System.err.println("处理文件时出错:" + file.getAbsolutePath() + ",错误信息:" + e.getMessage());
|
|
System.err.println("处理文件时出错:" + file.getAbsolutePath() + ",错误信息:" + e.getMessage());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
private Boolean fileExists(Long projectId, Long contractId, String folderName){
|
|
private Boolean fileExists(Long projectId, Long contractId, String folderName){
|
|
Integer i = scanFileMapper.exists(projectId, contractId, folderName);
|
|
Integer i = scanFileMapper.exists(projectId, contractId, folderName);
|
|
if(i==1){
|
|
if(i==1){
|
|
@@ -286,4 +327,57 @@ public class ScanFileServiceImpl extends ServiceImpl<ScanFileMapper, ScanFile>
|
|
return false;
|
|
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;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|