feat(printer): 引入照片处理管线机制

- 新增Crop和PrinterOrderItem模型用于封装裁剪信息和打印订单项
- 实现基于Pipeline模式的照片处理流程,支持普通照片和拼图处理
- 添加多个处理阶段:下载、方向检测、条件旋转、水印、恢复方向、上传和清理
- 创建PipelineBuilder用于动态构建处理管线
- 实现抽象Stage基类和具体Stage实现类
- 添加Stage执行结果管理和异常处理机制
- 优化照片处理逻辑,使用管线替代原有复杂的嵌套处理代码
- 支持通过景区配置管理水印类型、存储适配器等参数
- 提供临时文件管理工具确保处理过程中文件及时清理
- 增强日志记录和错误处理能力,提升系统可维护性
This commit is contained in:
2025-11-24 21:07:52 +08:00
parent 4360ef1313
commit e418a5ccdb
20 changed files with 1393 additions and 165 deletions

View File

@@ -0,0 +1,119 @@
package com.ycwl.basic.image.pipeline.util;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* 临时文件管理器
* 统一管理所有临时文件的创建和清理
*/
@Slf4j
public class TempFileManager {
private final String processId;
private final Path tempDir;
private final List<File> tempFiles;
public TempFileManager() {
this.processId = UUID.randomUUID().toString();
this.tempDir = initTempDirectory();
this.tempFiles = new ArrayList<>();
}
public TempFileManager(String processId) {
this.processId = processId;
this.tempDir = initTempDirectory();
this.tempFiles = new ArrayList<>();
}
private Path initTempDirectory() {
try {
Path systemTempDir = Files.createTempDirectory("photo_process_");
log.debug("创建临时目录: {}", systemTempDir);
return systemTempDir;
} catch (IOException e) {
log.warn("无法创建系统临时目录,使用当前目录", e);
return Path.of(".");
}
}
/**
* 创建临时文件
*
* @param prefix 文件名前缀
* @param suffix 文件名后缀(如 .jpg, .png)
* @return 临时文件
*/
public File createTempFile(String prefix, String suffix) {
String filename = String.format("%s_%s%s", prefix, processId, suffix);
File tempFile = tempDir.resolve(filename).toFile();
tempFiles.add(tempFile);
log.debug("创建临时文件: {}", tempFile.getAbsolutePath());
return tempFile;
}
/**
* 注册外部创建的临时文件
*/
public void registerTempFile(File file) {
if (file != null && !tempFiles.contains(file)) {
tempFiles.add(file);
log.debug("注册临时文件: {}", file.getAbsolutePath());
}
}
/**
* 清理所有临时文件
*/
public void cleanup() {
int deletedCount = 0;
int failedCount = 0;
for (File file : tempFiles) {
if (file != null && file.exists()) {
boolean deleted = file.delete();
if (deleted) {
deletedCount++;
log.debug("删除临时文件: {}", file.getAbsolutePath());
} else {
failedCount++;
log.warn("无法删除临时文件: {}", file.getAbsolutePath());
}
}
}
tempFiles.clear();
if (deletedCount > 0) {
log.info("清理临时文件: 成功{}个, 失败{}个", deletedCount, failedCount);
}
cleanupTempDirectory();
}
private void cleanupTempDirectory() {
if (tempDir != null && !tempDir.equals(Path.of("."))) {
try {
Files.deleteIfExists(tempDir);
log.debug("删除临时目录: {}", tempDir);
} catch (IOException e) {
log.warn("无法删除临时目录: {}", tempDir, e);
}
}
}
public String getProcessId() {
return processId;
}
public int getTempFileCount() {
return tempFiles.size();
}
}