文件下载修改
This commit is contained in:
parent
b1b4077ca5
commit
dae8527004
|
|
@ -50,7 +50,11 @@ public class ExportExcelService {
|
|||
|
||||
private static final String REDIS_KEY_PREFIX = "export:task:";
|
||||
// private static final String TEMP_PATH = System.getProperty("java.io.tmpdir") + File.separator + "export_task" + File.separator;
|
||||
private static final String TEMP_PATH = BonusConfig.getLsFile() + File.separator + "export_task" + File.separator;
|
||||
// private final String TEMP_PATH = BonusConfig.getLsFile() + File.separator + "export_task" + File.separator;
|
||||
|
||||
private String getTempPath() {
|
||||
return BonusConfig.getLsFile() + File.separator + "export_task" + File.separator;
|
||||
}
|
||||
|
||||
public String createExportTask(ParamsDto dto) {
|
||||
String taskId = UUID.randomUUID().toString();
|
||||
|
|
@ -68,25 +72,31 @@ public class ExportExcelService {
|
|||
try {
|
||||
Date start = dto.getStartTime();
|
||||
Date end = dto.getEndTime();
|
||||
|
||||
// 预先转换好由于比较的 LocalDate
|
||||
LocalDate startLD = toLocalDate(start);
|
||||
LocalDate endLD = toLocalDate(end);
|
||||
long dayDiff = DateUtil.between(start, end, DateUnit.DAY);
|
||||
|
||||
File tempDir = new File(TEMP_PATH);
|
||||
long dayDiff = DateUtil.between(start, end, DateUnit.DAY);
|
||||
log.info("任务[{}] 临时路径:{}", taskId, getTempPath());
|
||||
|
||||
File tempDir = new File(getTempPath());
|
||||
if (!tempDir.exists()) tempDir.mkdirs();
|
||||
|
||||
File finalResultFile;
|
||||
String downloadFileName;
|
||||
|
||||
if (dayDiff <= 0) {
|
||||
// 单天任务:直接处理
|
||||
// --- 单天任务逻辑保持不变 ---
|
||||
downloadFileName = "数据识别_" + DateUtil.formatDate(start) + ".xlsx";
|
||||
finalResultFile = new File(TEMP_PATH + taskId + "_" + downloadFileName);
|
||||
finalResultFile = new File(getTempPath() + taskId + "_" + downloadFileName);
|
||||
generateExcel(finalResultFile, start, end, taskId, 0, 100, true);
|
||||
} else {
|
||||
// 多天任务:多线程处理
|
||||
// --- 多天任务:多线程处理 ---
|
||||
List<Date> dateRange = getDatesBetween(start, end);
|
||||
int totalDays = dateRange.size();
|
||||
|
||||
// 使用同步列表保证添加安全
|
||||
List<File> subFiles = Collections.synchronizedList(new ArrayList<>());
|
||||
CountDownLatch latch = new CountDownLatch(totalDays);
|
||||
AtomicInteger finishedCount = new AtomicInteger(0);
|
||||
|
|
@ -95,34 +105,40 @@ public class ExportExcelService {
|
|||
exportThreadPool.execute(() -> {
|
||||
try {
|
||||
String subFileName = taskId + "_数据识别_" + DateUtil.formatDate(currentDate) + ".xlsx";
|
||||
File subFile = new File(TEMP_PATH + subFileName);
|
||||
// 传入 false,表示子线程不直接更新 Redis 整体进度,由主线程负责更新
|
||||
LocalDate currentLD = toLocalDate(end);
|
||||
// 进行逻辑判断
|
||||
boolean isSameAsStart = currentLD.equals(startLD);
|
||||
boolean isSameAsEnd = currentLD.equals(endLD);
|
||||
if (isSameAsStart && !isSameAsEnd) {
|
||||
// 情况 1:仅与开始日期相同
|
||||
LocalDateTime endOfDay = currentLD.atTime(LocalTime.MAX);
|
||||
Date endDate = Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
|
||||
generateExcel(subFile, start, endDate, taskId, -1, -1, false);
|
||||
} else if (!isSameAsStart && isSameAsEnd) {
|
||||
// 情况 2:仅与结束日期相同
|
||||
Date startDate = Date.from(currentLD.atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
generateExcel(subFile, startDate, end, taskId, -1, -1, false);
|
||||
} else if (!isSameAsStart && !isSameAsEnd) {
|
||||
// 情况 3:都不同
|
||||
Date startDate = Date.from(currentLD.atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
LocalDateTime endOfDay = currentLD.atTime(LocalTime.MAX);
|
||||
Date endDate = Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
|
||||
generateExcel(subFile, startDate, endDate, taskId, -1, -1, false);
|
||||
File subFile = new File(getTempPath() + subFileName);
|
||||
|
||||
// [关键修复] 获取当前循环日期的 LocalDate
|
||||
LocalDate currentLD = toLocalDate(currentDate);
|
||||
|
||||
// [逻辑简化] 计算当前切片的起止时间
|
||||
Date sliceStartTime;
|
||||
Date sliceEndTime;
|
||||
|
||||
// 1. 确定开始时间:如果是第一天,用全局start;否则用当天的 00:00:00
|
||||
if (currentLD.equals(startLD)) {
|
||||
sliceStartTime = start;
|
||||
} else {
|
||||
sliceStartTime = Date.from(currentLD.atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
|
||||
// 2. 确定结束时间:如果是最后一天,用全局end;否则用当天的 23:59:59
|
||||
if (currentLD.equals(endLD)) {
|
||||
sliceEndTime = end;
|
||||
} else {
|
||||
LocalDateTime endOfDay = currentLD.atTime(LocalTime.MAX);
|
||||
sliceEndTime = Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
|
||||
// 执行生成 (updateProgress=false)
|
||||
generateExcel(subFile, sliceStartTime, sliceEndTime, taskId, -1, -1, false);
|
||||
|
||||
subFiles.add(subFile);
|
||||
} catch (Exception e) {
|
||||
log.error("子任务执行失败: {}", currentDate, e);
|
||||
log.error("子任务[{}] 日期[{}] 执行失败", taskId, DateUtil.formatDate(currentDate), e);
|
||||
// 可以在这里记录失败的子文件,或者抛出异常让主流程感知
|
||||
} finally {
|
||||
// 更新整体进度:0-95%
|
||||
int finished = finishedCount.incrementAndGet();
|
||||
// 进度条平滑处理,保留最后几秒给打包
|
||||
int currentProgress = (int) ((double) finished / totalDays * 95);
|
||||
updateStatusProgress(taskId, currentProgress, "running");
|
||||
latch.countDown();
|
||||
|
|
@ -130,21 +146,35 @@ public class ExportExcelService {
|
|||
});
|
||||
}
|
||||
|
||||
// 最多等待子任务处理 30 分钟
|
||||
latch.await(30, TimeUnit.MINUTES);
|
||||
// 等待所有子任务完成
|
||||
boolean allFinished = latch.await(30, TimeUnit.MINUTES);
|
||||
if (!allFinished) {
|
||||
log.warn("任务[{}] 部分子线程超时,正在打包已完成部分", taskId);
|
||||
}
|
||||
|
||||
updateStatusProgress(taskId, 96, "running");
|
||||
|
||||
// [优化] 排序子文件。多线程执行完顺序是乱的,按文件名(日期)排序后再打包,解压后体验更好
|
||||
subFiles.sort(Comparator.comparing(File::getName));
|
||||
|
||||
updateStatusProgress(taskId, 98, "running");
|
||||
String dateRangeStr = DateUtil.format(start, "yyyyMMdd") + "-" + DateUtil.format(end, "yyyyMMdd");
|
||||
downloadFileName = "批量数据识别_" + dateRangeStr + ".zip";
|
||||
finalResultFile = new File(TEMP_PATH + taskId + ".zip");
|
||||
finalResultFile = new File(getTempPath() + taskId + ".zip");
|
||||
|
||||
ZipUtil.zip(finalResultFile, false, subFiles.toArray(new File[0]));
|
||||
subFiles.forEach(File::delete);
|
||||
// 只有当有文件生成时才打包
|
||||
if (!subFiles.isEmpty()) {
|
||||
ZipUtil.zip(finalResultFile, false, subFiles.toArray(new File[0]));
|
||||
// 删除临时子文件
|
||||
subFiles.forEach(File::delete);
|
||||
} else {
|
||||
throw new RuntimeException("未能生成任何数据文件");
|
||||
}
|
||||
}
|
||||
|
||||
// 完成任务更新
|
||||
completeTask(taskId, finalResultFile, downloadFileName);
|
||||
} catch (Exception e) {
|
||||
log.error("导出任务异常", e);
|
||||
handleError(taskId, e);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,12 @@ public class ExportService {
|
|||
|
||||
// 临时文件存放目录
|
||||
// private static final String TEMP_DIR = System.getProperty("java.io.tmpdir") + "/export_task/";
|
||||
private static final String TEMP_DIR = BonusConfig.getLsFile() + "/export_task/";
|
||||
// private final String TEMP_DIR = BonusConfig.getLsFile() + "/export_task/";
|
||||
// private final String TEMP_DIR = BonusConfig.getLsFile() + "/export_task/";
|
||||
|
||||
private String getTempDir() {
|
||||
return BonusConfig.getLsFile() + File.separator + "export_task" + File.separator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建任务并立即返回 TaskID
|
||||
|
|
@ -121,7 +126,7 @@ public class ExportService {
|
|||
groupedImages.computeIfAbsent(dateStr, k -> new ArrayList<>()).add(img);
|
||||
}
|
||||
|
||||
File tempDir = new File(TEMP_DIR);
|
||||
File tempDir = new File(getTempDir());
|
||||
if (!tempDir.exists()) tempDir.mkdirs();
|
||||
|
||||
String masterFileName = "图像识别数据_" + System.currentTimeMillis() + ".zip";
|
||||
|
|
@ -200,12 +205,12 @@ public class ExportService {
|
|||
*/
|
||||
private File createDailyZip(String dateStr, List<ImageRecord> images) throws IOException {
|
||||
// 确保临时目录存在
|
||||
File tempDir = new File(TEMP_DIR);
|
||||
File tempDir = new File(getTempDir());
|
||||
if (!tempDir.exists()) {
|
||||
tempDir.mkdirs();
|
||||
}
|
||||
|
||||
File dailyZip = new File(TEMP_DIR, "temp_" + dateStr + "_" + UUID.randomUUID() + ".zip");
|
||||
File dailyZip = new File(getTempDir(), "temp_" + dateStr + "_" + UUID.randomUUID() + ".zip");
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(dailyZip);
|
||||
ZipOutputStream dailyZos = new ZipOutputStream(fos)) {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public interface DILineService {
|
|||
* 删除线的坐标
|
||||
* @return void
|
||||
* @author cwchen
|
||||
* @date 2026/1/20 14:29
|
||||
* @date 2026/1/20 14:52
|
||||
*/
|
||||
void deleteLine();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,15 +24,17 @@ public class FileCleanupTask {
|
|||
|
||||
// 使用之前定义的临时目录路径
|
||||
// private static final String TEMP_PATH = System.getProperty("java.io.tmpdir") + File.separator + "export_task" + File.separator;
|
||||
private static final String TEMP_PATH = BonusConfig.getLsFile() + File.separator + "export_task" + File.separator;
|
||||
|
||||
// private final String TEMP_PATH = BonusConfig.getLsFile() + File.separator + "export_task" + File.separator;
|
||||
private String getTempPath() {
|
||||
return BonusConfig.getLsFile() + File.separator + "export_task" + File.separator;
|
||||
}
|
||||
/**
|
||||
* 每天凌晨 2 点执行清理任务
|
||||
* cron 表达式: 秒 分 时 日 月 周
|
||||
*/
|
||||
public void cleanupTempFiles() {
|
||||
log.info("开始执行导出临时文件清理任务...");
|
||||
File directory = new File(TEMP_PATH);
|
||||
File directory = new File(getTempPath());
|
||||
|
||||
if (!directory.exists() || !directory.isDirectory()) {
|
||||
log.info("临时目录不存在,跳过清理。");
|
||||
|
|
|
|||
Loading…
Reference in New Issue