Fix: 修复文件上传临时文件丢失问题
问题: - Docker 环境下上传文件时出现 FileNotFoundException - Tomcat 在异步任务执行前清理了临时文件 /tmp/tomcat.xxx/work/... 解决方案: 1. 配置 multipart.location 为持久化目录 ./data/upload-temp 2. 设置 file-size-threshold: 0 强制立即写入磁盘 3. 修改 SftpController.upload() 方法: - 在异步任务执行前将 MultipartFile 保存到持久化位置 - 异步任务从保存的文件读取而非 MultipartFile.getInputStream() - 上传完成或失败后自动清理临时文件 影响范围: - backend/src/main/resources/application.yml - backend/src/main/java/com/sshmanager/controller/SftpController.java
This commit is contained in:
@@ -290,11 +290,21 @@ public class SftpController {
|
|||||||
@RequestParam String path,
|
@RequestParam String path,
|
||||||
@RequestParam("file") MultipartFile file,
|
@RequestParam("file") MultipartFile file,
|
||||||
Authentication authentication) {
|
Authentication authentication) {
|
||||||
|
java.io.File tempFile = null;
|
||||||
try {
|
try {
|
||||||
Long userId = getCurrentUserId(authentication);
|
Long userId = getCurrentUserId(authentication);
|
||||||
String taskId = UUID.randomUUID().toString();
|
String taskId = UUID.randomUUID().toString();
|
||||||
String taskKey = uploadTaskKey(userId, taskId);
|
String taskKey = uploadTaskKey(userId, taskId);
|
||||||
|
|
||||||
|
// Save file to persistent location before async processing
|
||||||
|
java.io.File uploadTempDir = new java.io.File("./data/upload-temp");
|
||||||
|
if (!uploadTempDir.exists()) {
|
||||||
|
uploadTempDir.mkdirs();
|
||||||
|
}
|
||||||
|
tempFile = new java.io.File(uploadTempDir, taskId + "_" + file.getOriginalFilename());
|
||||||
|
file.transferTo(tempFile);
|
||||||
|
final java.io.File savedFile = tempFile;
|
||||||
|
|
||||||
UploadTaskStatus status = new UploadTaskStatus(taskId, userId, connectionId,
|
UploadTaskStatus status = new UploadTaskStatus(taskId, userId, connectionId,
|
||||||
path, file.getOriginalFilename(), file.getSize());
|
path, file.getOriginalFilename(), file.getSize());
|
||||||
status.setController(this);
|
status.setController(this);
|
||||||
@@ -308,11 +318,11 @@ public class SftpController {
|
|||||||
try {
|
try {
|
||||||
SftpService.SftpSession session = getOrCreateSession(connectionId, userId);
|
SftpService.SftpSession session = getOrCreateSession(connectionId, userId);
|
||||||
String remotePath = (path == null || path.isEmpty() || path.equals("/"))
|
String remotePath = (path == null || path.isEmpty() || path.equals("/"))
|
||||||
? "/" + file.getOriginalFilename()
|
? "/" + savedFile.getName().substring(savedFile.getName().indexOf("_") + 1)
|
||||||
: (path.endsWith("/") ? path + file.getOriginalFilename() : path + "/" + file.getOriginalFilename());
|
: (path.endsWith("/") ? path + savedFile.getName().substring(savedFile.getName().indexOf("_") + 1) : path + "/" + savedFile.getName().substring(savedFile.getName().indexOf("_") + 1));
|
||||||
|
|
||||||
AtomicLong transferred = new AtomicLong(0);
|
AtomicLong transferred = new AtomicLong(0);
|
||||||
try (java.io.InputStream in = file.getInputStream()) {
|
try (java.io.InputStream in = new java.io.FileInputStream(savedFile)) {
|
||||||
sftpService.upload(session, remotePath, in, new SftpService.TransferProgressListener() {
|
sftpService.upload(session, remotePath, in, new SftpService.TransferProgressListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onStart(long totalBytes) {
|
public void onStart(long totalBytes) {
|
||||||
@@ -334,10 +344,19 @@ public class SftpController {
|
|||||||
existing.disconnect();
|
existing.disconnect();
|
||||||
}
|
}
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
// Clean up temp file after upload completes
|
||||||
|
if (savedFile.exists()) {
|
||||||
|
savedFile.delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
status.markError(e.getMessage() != null ? e.getMessage() : "Upload failed");
|
status.markError(e.getMessage() != null ? e.getMessage() : "Upload failed");
|
||||||
|
// Clean up temp file on error
|
||||||
|
if (savedFile.exists()) {
|
||||||
|
savedFile.delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
status.setFuture(future);
|
status.setFuture(future);
|
||||||
@@ -347,6 +366,10 @@ public class SftpController {
|
|||||||
result.put("message", "Upload started");
|
result.put("message", "Upload started");
|
||||||
return ResponseEntity.ok(result);
|
return ResponseEntity.ok(result);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
// Clean up temp file if initial save failed
|
||||||
|
if (tempFile != null && tempFile.exists()) {
|
||||||
|
tempFile.delete();
|
||||||
|
}
|
||||||
Map<String, Object> error = new HashMap<>();
|
Map<String, Object> error = new HashMap<>();
|
||||||
error.put("error", e.getMessage());
|
error.put("error", e.getMessage());
|
||||||
return ResponseEntity.status(500).body(error);
|
return ResponseEntity.status(500).body(error);
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ spring:
|
|||||||
multipart:
|
multipart:
|
||||||
max-file-size: 2048MB
|
max-file-size: 2048MB
|
||||||
max-request-size: 2048MB
|
max-request-size: 2048MB
|
||||||
|
location: ./data/upload-temp
|
||||||
|
file-size-threshold: 0
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:h2:file:./data/sshmanager;DB_CLOSE_DELAY=-1
|
url: jdbc:h2:file:./data/sshmanager;DB_CLOSE_DELAY=-1
|
||||||
driver-class-name: org.h2.Driver
|
driver-class-name: org.h2.Driver
|
||||||
|
|||||||
Reference in New Issue
Block a user