package com.ard.inspection.service.impl;
|
|
import com.ard.common.core.domain.AjaxResult;
|
import com.ard.common.utils.uuid.IdUtils;
|
import com.ard.inspection.domain.ArdPointCloud;
|
import com.ard.inspection.domain.UploadFileEntity;
|
import com.ard.inspection.service.IArdPointCloudService;
|
import com.ard.inspection.service.IBigFileUploadService;
|
import com.ard.inspection.utils.ZipFileUtils;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.web.multipart.MultipartFile;
|
|
import javax.annotation.Resource;
|
import java.io.File;
|
import java.io.IOException;
|
import java.io.RandomAccessFile;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
import static com.ard.inspection.utils.ZipFileUtils.formatFileSize;
|
|
/**
|
* @author xia
|
*/
|
@Service
|
@Slf4j
|
public class BigFileUploadServiceImpl implements IBigFileUploadService {
|
|
public static final String CLOUD_FILE_PATH = "https://192.168.1.3:3001/tileset/";
|
|
@Autowired
|
private IArdPointCloudService ardPointCloudService;
|
|
@Resource
|
private ZipFileUtils zipFileUtils;
|
|
@Override
|
public Map<String, Object> checkChunk(String fileMd5,String chunkPath) {
|
Map<String, Object> result = new HashMap<>();
|
try {
|
File chunkFolder = new File(chunkPath + File.separator + fileMd5);
|
if (!chunkFolder.exists()) {
|
result.put("exception", "分片不存在!!!");
|
return result;
|
}
|
|
File[] chunks = chunkFolder.listFiles();
|
if (chunks == null || chunks.length == 0) {
|
result.put("exception", "无分片!!!");
|
return result;
|
}
|
|
List<Integer> uploadedChunks = Arrays.stream(chunks)
|
.map(file -> Integer.parseInt(file.getName().split("\\.")[0]))
|
.collect(Collectors.toList());
|
result.put("message", uploadedChunks);
|
return result;
|
} catch (Exception e) {
|
log.error("检查分片失败", e);
|
result.put("exception", "检查分片失败!!!");
|
return result;
|
}
|
}
|
|
@Override
|
public Map<String, Object> uploadChunk(MultipartFile file,
|
Integer chunkNumber,
|
String fileMd5,
|
String chunkPath) {
|
Map<String, Object> result = new HashMap<>();
|
try {
|
// 验证参数
|
if (file.isEmpty()) {
|
result.put("exception", "文件不能为空!!!");
|
return result;
|
}
|
|
// 创建分片目录
|
String chunkDirPath = chunkPath + File.separator + fileMd5;
|
File chunkDir = new File(chunkDirPath);
|
if (!chunkDir.exists()) {
|
chunkDir.mkdirs();
|
}
|
|
// 保存分片
|
String chunkFileName = chunkNumber + ".part";
|
File chunkFile = new File(chunkDir, chunkFileName);
|
file.transferTo(chunkFile);
|
|
result.put("message", "分片上传成功!!!");
|
return result;
|
} catch (IOException e) {
|
log.error("分片上传失败", e);
|
result.put("exception", "分片上传失败!!!");
|
return result;
|
}
|
}
|
|
@Override
|
public Map<String, Object> uploadChunk(MultipartFile file,UploadFileEntity uploadFileEntity,String chunkPath) {
|
Map<String, Object> result = new HashMap<>();
|
try {
|
// 验证参数
|
if (file.isEmpty()) {
|
result.put("exception", "文件不能为空!!!");
|
return result;
|
}
|
|
// 创建分片目录
|
String chunkDirPath = chunkPath + File.separator + uploadFileEntity.getFileMd5();
|
File chunkDir = new File(chunkDirPath);
|
if (!chunkDir.exists()) {
|
chunkDir.mkdirs();
|
}
|
|
// 保存分片
|
String chunkFileName = uploadFileEntity.getChunkNumber() + ".part";
|
File chunkFile = new File(chunkDir, chunkFileName);
|
file.transferTo(chunkFile);
|
|
result.put("message", "分片上传成功!!!");
|
return result;
|
} catch (IOException e) {
|
log.error("分片上传失败", e);
|
result.put("exception", "分片上传失败!!!");
|
return result;
|
}
|
}
|
|
@Override
|
public Map<String, Object> mergeChunks(String md5,String fileName,String uploadPath) {
|
Map<String, Object> result = new HashMap<>();
|
// 临时目录
|
String chunkDir = uploadPath + File.separator + md5;
|
File dir = new File(chunkDir);
|
if (!dir.exists()) {
|
result.put("exception", "切片目录不存在");
|
return result;
|
}
|
// 获取所有切片文件
|
File[] chunks = dir.listFiles();
|
if (chunks == null || chunks.length == 0) {
|
result.put("exception", "没有切片文件");
|
return result;
|
}
|
// 按照切片索引排序
|
Arrays.sort(chunks, (a, b) -> {
|
int aIndex = Integer.parseInt(a.getName().split("\\.")[0]);
|
int bIndex = Integer.parseInt(b.getName().split("\\.")[0]);
|
return aIndex - bIndex;
|
});
|
|
// 合并后的文件,这里使用原始文件名,为了避免重名,可以加上时间戳或使用UUID
|
// 这里根据业务需求,可以保存到数据库,记录文件路径等信息
|
String ext = fileName.substring(fileName.lastIndexOf("."));
|
String newFileName = UUID.randomUUID().toString().replace("-", "") + ext; // 生成新文件名
|
File mergeFile = new File(uploadPath, newFileName);
|
|
try (RandomAccessFile randomAccessFile = new RandomAccessFile(mergeFile, "rw")) {
|
byte[] buffer = new byte[1024 * 1024]; // 1MB缓冲区
|
for (File chunk : chunks) {
|
try (RandomAccessFile chunkFile = new RandomAccessFile(chunk, "r")) {
|
int len;
|
while ((len = chunkFile.read(buffer)) != -1) {
|
randomAccessFile.write(buffer, 0, len);
|
}
|
}
|
// 删除切片文件
|
chunk.delete();
|
}
|
// 删除临时目录
|
dir.delete();
|
} catch (IOException e) {
|
log.error("合并文件失败", e);
|
result.put("exception", "合并文件失败");
|
return result;
|
}
|
|
// 这里可以保存文件信息到数据库,例如文件路径、文件名、md5等
|
// fileService.saveFileInfo(...);
|
// ArdPointCloud ardPointCloud = new ArdPointCloud();
|
// ardPointCloud.setFileName(newFileName);
|
// ardPointCloud.setFileSize(mergeFile.length());
|
// ardPointCloud.setAssociatedState("0");
|
// ardPointCloudService.insertArdPointCloud(ardPointCloud);
|
|
result.put("message", "文件合并成功");
|
return result;
|
}
|
|
/**
|
* 大文件上传并解压接口
|
* @param file 上传的ZIP文件
|
* @param overwrite 是否覆盖已存在文件(默认false)
|
* @param uploadPath 上传文件存储路径
|
* @param chunkPath 临时切片存储路径
|
* @param zipPath 解压文件存储路径
|
* @return 上传结果
|
*/
|
@Override
|
public AjaxResult uploadBigZipFile(MultipartFile file, boolean overwrite,
|
String uploadPath,
|
String chunkPath,
|
String zipPath) {
|
// 1. 校验文件是否为空
|
if (file.isEmpty()) {
|
return AjaxResult.error("上传文件不能为空");
|
}
|
|
// 2. 校验文件格式
|
String originalFilename = file.getOriginalFilename();
|
if (originalFilename == null || !originalFilename.endsWith(".zip")) {
|
return AjaxResult.error("仅支持ZIP格式文件上传");
|
}
|
|
// 2.1 校验文件名是否重复
|
if (!overwrite) {
|
if (ardPointCloudService.selectArdPointCloudByFileName(originalFilename) != null) {
|
return AjaxResult.error("文件已存在");
|
}
|
}
|
|
// 3. 创建临时目录
|
File tempDir = new File(uploadPath);
|
if (!tempDir.exists()) {
|
boolean mkdirs = tempDir.mkdirs();
|
if (!mkdirs) {
|
return AjaxResult.error("创建临时上传目录失败");
|
}
|
}
|
|
// 4. 保存上传的ZIP文件到临时目录(避免重名)
|
String tempFileName = UUID.randomUUID() + ".zip";
|
File tempFile = new File(chunkPath + File.separator + tempFileName);
|
try {
|
file.transferTo(tempFile);
|
log.info("临时文件保存成功:{},文件大小:{}MB", tempFile.getAbsolutePath(),
|
file.getSize() / 1024 / 1024);
|
} catch (IOException e) {
|
log.error("保存临时文件失败", e);
|
return AjaxResult.error("文件上传失败:" + e.getMessage());
|
}
|
|
// 5. 解压文件
|
try {
|
zipFileUtils.unzip(tempFile.getAbsolutePath(), overwrite);
|
// 6. 删除临时文件(可选,若需要保留压缩包可注释)
|
boolean delete = tempFile.delete();
|
if (delete) {
|
log.info("临时文件已删除:{}", tempFile.getAbsolutePath());
|
}
|
ArdPointCloud ardPointCloud = new ArdPointCloud();
|
ardPointCloud.setFileName(originalFilename);
|
ardPointCloud.setFileSize(formatFileSize(file.getSize()));
|
int dotIndex = originalFilename.lastIndexOf('.');
|
String folderName = (dotIndex > 0) ? originalFilename.substring(0, dotIndex) : originalFilename;
|
String zipP = CLOUD_FILE_PATH + folderName + "/tileset.json";
|
ardPointCloud.setFilePath(zipP);
|
ardPointCloud.setFolderName(folderName);
|
return AjaxResult.success("文件上传并解压成功", ardPointCloud);
|
} catch (IOException e) {
|
log.error("解压文件失败", e);
|
// 失败时删除临时文件
|
if (tempFile.exists()) {
|
tempFile.delete();
|
}
|
return AjaxResult.error("文件解压失败:" + e.getMessage());
|
}
|
}
|
|
}
|