- 在 application.yml 和环境特定的配置文件中添加文件存储目录路径配置 - 新增 Stage 环境配置文件和相关设置 - 修改 WmsFileManagementController 以使用配置文件中的目录路径 - 优化文件管理相关 API 的错误处理和路径获取方式
378 lines
15 KiB
Java
378 lines
15 KiB
Java
package com.klp.controller;
|
||
|
||
import com.klp.domain.FileDetailInfo;
|
||
import com.klp.domain.FileInfo;
|
||
import com.klp.domain.vo.ApiResponseVo;
|
||
import org.springframework.beans.factory.annotation.Value;
|
||
import org.springframework.web.bind.annotation.*;
|
||
import org.springframework.scheduling.annotation.Scheduled;
|
||
import org.springframework.stereotype.Controller;
|
||
import org.springframework.http.ResponseEntity;
|
||
import org.springframework.http.HttpStatus;
|
||
|
||
import java.io.*;
|
||
import java.nio.file.*;
|
||
import java.time.LocalDateTime;
|
||
import java.time.format.DateTimeFormatter;
|
||
import java.util.*;
|
||
import java.util.stream.Collectors;
|
||
|
||
/**
|
||
* WMS文件管理控制器
|
||
* 提供文件读取、删除和定时删除功能
|
||
*/
|
||
@Controller
|
||
@RequestMapping("/wms/file")
|
||
public class WmsFileManagementController {
|
||
|
||
// 文件目录路径 - 从配置文件读取
|
||
@Value("${klp.file.directory-path}")
|
||
private String directoryPath;
|
||
|
||
/**
|
||
* 获取目录下所有文件基本信息(不包含文件内容)
|
||
* GET /wms/file/list
|
||
*/
|
||
@GetMapping("/list")
|
||
@ResponseBody
|
||
public ResponseEntity<ApiResponseVo<List<FileInfo>>> getAllFiles() {
|
||
try {
|
||
Path directory = Paths.get(directoryPath);
|
||
|
||
// 检查目录是否存在
|
||
if (!Files.exists(directory)) {
|
||
return ResponseEntity.ok(new ApiResponseVo<>(false, "目录不存在: " + directoryPath, null));
|
||
}
|
||
|
||
// 获取所有文件基本信息(不读取文件内容)
|
||
List<FileInfo> fileList = new ArrayList<>();
|
||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory)) {
|
||
for (Path file : stream) {
|
||
if (Files.isRegularFile(file)) {
|
||
FileInfo fileInfo = readFileBasicInfo(file);
|
||
fileList.add(fileInfo);
|
||
}
|
||
}
|
||
}
|
||
|
||
String message = String.format("成功获取 %d 个文件", fileList.size());
|
||
return ResponseEntity.ok(new ApiResponseVo<>(true, message, fileList));
|
||
|
||
} catch (Exception e) {
|
||
String errorMsg = "获取文件列表失败: " + e.getMessage();
|
||
System.err.println(errorMsg);
|
||
e.printStackTrace();
|
||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||
.body(new ApiResponseVo<>(false, errorMsg, null));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取单个文件的详细信息(包含文件内容)
|
||
* GET /wms/file/content/{fileName}
|
||
*/
|
||
@GetMapping("/content/{fileName}")
|
||
@ResponseBody
|
||
public ResponseEntity<ApiResponseVo<FileDetailInfo>> getFileContent(@PathVariable String fileName) {
|
||
try {
|
||
Path filePath = Paths.get(directoryPath, fileName);
|
||
|
||
// 检查文件是否存在
|
||
if (!Files.exists(filePath)) {
|
||
return ResponseEntity.ok(new ApiResponseVo<>(false, "文件不存在: " + fileName, null));
|
||
}
|
||
|
||
// 检查是否为普通文件
|
||
if (!Files.isRegularFile(filePath)) {
|
||
return ResponseEntity.ok(new ApiResponseVo<>(false, "不是普通文件: " + fileName, null));
|
||
}
|
||
|
||
// 读取文件详细信息(包含内容)
|
||
FileDetailInfo fileDetailInfo = readFileDetailInfo(filePath);
|
||
|
||
String message = "成功获取文件内容: " + fileName;
|
||
return ResponseEntity.ok(new ApiResponseVo<>(true, message, fileDetailInfo));
|
||
|
||
} catch (Exception e) {
|
||
String errorMsg = "获取文件内容失败: " + e.getMessage();
|
||
System.err.println(errorMsg);
|
||
e.printStackTrace();
|
||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||
.body(new ApiResponseVo<>(false, errorMsg, null));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 根据文件名删除文件
|
||
* DELETE /wms/file/delete/{fileName}
|
||
*/
|
||
@DeleteMapping("/delete/{fileName}")
|
||
@ResponseBody
|
||
public ResponseEntity<ApiResponseVo<String>> deleteFile(@PathVariable String fileName) {
|
||
try {
|
||
Path filePath = Paths.get(directoryPath, fileName);
|
||
|
||
// 检查文件是否存在
|
||
if (!Files.exists(filePath)) {
|
||
return ResponseEntity.ok(new ApiResponseVo<>(false, "文件不存在: " + fileName, null));
|
||
}
|
||
|
||
// 检查是否为普通文件
|
||
if (!Files.isRegularFile(filePath)) {
|
||
return ResponseEntity.ok(new ApiResponseVo<>(false, "不是普通文件: " + fileName, null));
|
||
}
|
||
|
||
// 删除文件
|
||
Files.delete(filePath);
|
||
|
||
String message = "文件删除成功: " + fileName;
|
||
return ResponseEntity.ok(new ApiResponseVo<>(true, message, fileName));
|
||
|
||
} catch (Exception e) {
|
||
String errorMsg = "删除文件失败: " + e.getMessage();
|
||
System.err.println(errorMsg);
|
||
e.printStackTrace();
|
||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||
.body(new ApiResponseVo<>(false, errorMsg, null));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 批量删除文件
|
||
* POST /wms/file/batch-delete
|
||
*/
|
||
@PostMapping("/batch-delete")
|
||
@ResponseBody
|
||
public ResponseEntity<ApiResponseVo<Map<String, Object>>> batchDeleteFiles(@RequestBody List<String> fileNames) {
|
||
try {
|
||
Map<String, Object> result = new HashMap<>();
|
||
List<String> successList = new ArrayList<>();
|
||
List<String> failedList = new ArrayList<>();
|
||
|
||
for (String fileName : fileNames) {
|
||
try {
|
||
Path filePath = Paths.get(directoryPath, fileName);
|
||
|
||
if (Files.exists(filePath) && Files.isRegularFile(filePath)) {
|
||
Files.delete(filePath);
|
||
successList.add(fileName);
|
||
} else {
|
||
failedList.add(fileName + " (文件不存在)");
|
||
}
|
||
} catch (Exception e) {
|
||
failedList.add(fileName + " (" + e.getMessage() + ")");
|
||
}
|
||
}
|
||
|
||
result.put("successCount", successList.size());
|
||
result.put("failedCount", failedList.size());
|
||
result.put("successFiles", successList);
|
||
result.put("failedFiles", failedList);
|
||
|
||
String message = String.format("批量删除完成: 成功 %d 个, 失败 %d 个",
|
||
successList.size(), failedList.size());
|
||
|
||
return ResponseEntity.ok(new ApiResponseVo<>(true, message, result));
|
||
|
||
} catch (Exception e) {
|
||
String errorMsg = "批量删除失败: " + e.getMessage();
|
||
System.err.println(errorMsg);
|
||
e.printStackTrace();
|
||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||
.body(new ApiResponseVo<>(false, errorMsg, null));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 手动执行定时删除(删除前3个月的文件)
|
||
* POST /wms/file/cleanup
|
||
*/
|
||
@PostMapping("/cleanup")
|
||
@ResponseBody
|
||
public ResponseEntity<ApiResponseVo<Map<String, Object>>> manualCleanup() {
|
||
return performCleanup();
|
||
}
|
||
|
||
/**
|
||
* 定时删除任务 - 每3个月执行一次
|
||
* 删除前3个月的文件(1-3个月前的文件)
|
||
*/
|
||
@Scheduled(cron = "0 0 2 1 */3 *") // 每3个月的第1天凌晨2点执行
|
||
public void scheduledCleanup() {
|
||
System.out.println("=== 开始执行定时删除任务 ===");
|
||
System.out.println("执行时间: " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||
|
||
ResponseEntity<ApiResponseVo<Map<String, Object>>> response = performCleanup();
|
||
ApiResponseVo<Map<String, Object>> result = response.getBody();
|
||
|
||
if (result != null) {
|
||
System.out.println("定时删除结果: " + result.getMessage());
|
||
if (result.getData() != null) {
|
||
Map<String, Object> data = result.getData();
|
||
System.out.println("删除文件数量: " + data.get("deletedCount"));
|
||
System.out.println("删除的文件: " + data.get("deletedFiles"));
|
||
}
|
||
}
|
||
|
||
System.out.println("=== 定时删除任务完成 ===");
|
||
}
|
||
|
||
/**
|
||
* 执行清理操作
|
||
*/
|
||
private ResponseEntity<ApiResponseVo<Map<String, Object>>> performCleanup() {
|
||
try {
|
||
Path directory = Paths.get(directoryPath);
|
||
|
||
if (!Files.exists(directory)) {
|
||
return ResponseEntity.ok(new ApiResponseVo<>(false, "目录不存在: " + directoryPath, null));
|
||
}
|
||
|
||
// 计算时间范围:删除1-3个月前的文件
|
||
LocalDateTime oneMonthAgo = LocalDateTime.now().minusMonths(1);
|
||
LocalDateTime threeMonthsAgo = LocalDateTime.now().minusMonths(3);
|
||
|
||
List<String> deletedFiles = new ArrayList<>();
|
||
int deletedCount = 0;
|
||
|
||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory)) {
|
||
for (Path file : stream) {
|
||
if (Files.isRegularFile(file)) {
|
||
try {
|
||
// 获取文件最后修改时间
|
||
LocalDateTime fileModifiedTime = LocalDateTime.ofInstant(
|
||
Files.getLastModifiedTime(file).toInstant(),
|
||
java.time.ZoneId.systemDefault()
|
||
);
|
||
|
||
// 如果文件修改时间在1-3个月前之间,则删除
|
||
if (fileModifiedTime.isBefore(oneMonthAgo) && fileModifiedTime.isAfter(threeMonthsAgo)) {
|
||
Files.delete(file);
|
||
deletedFiles.add(file.getFileName().toString());
|
||
deletedCount++;
|
||
}
|
||
} catch (Exception e) {
|
||
System.err.println("删除文件失败: " + file.getFileName() + " - " + e.getMessage());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
Map<String, Object> result = new HashMap<>();
|
||
result.put("deletedCount", deletedCount);
|
||
result.put("deletedFiles", deletedFiles);
|
||
result.put("cleanupTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||
result.put("startTime", oneMonthAgo.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||
result.put("endTime", threeMonthsAgo.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||
|
||
String message = String.format("清理完成: 删除了 %d 个前3个月的文件", deletedCount);
|
||
return ResponseEntity.ok(new ApiResponseVo<>(true, message, result));
|
||
|
||
} catch (Exception e) {
|
||
String errorMsg = "清理操作失败: " + e.getMessage();
|
||
System.err.println(errorMsg);
|
||
e.printStackTrace();
|
||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||
.body(new ApiResponseVo<>(false, errorMsg, null));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 读取文件基本信息(不包含文件内容)
|
||
*/
|
||
private FileInfo readFileBasicInfo(Path filePath) throws IOException {
|
||
String fileName = filePath.getFileName().toString();
|
||
long fileSize = Files.size(filePath);
|
||
|
||
LocalDateTime lastModified = LocalDateTime.ofInstant(
|
||
Files.getLastModifiedTime(filePath).toInstant(),
|
||
java.time.ZoneId.systemDefault()
|
||
);
|
||
String lastModifiedStr = lastModified.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||
|
||
return new FileInfo(fileName, fileSize, lastModifiedStr, filePath.toString());
|
||
}
|
||
|
||
/**
|
||
* 读取文件详细信息(包含文件内容)
|
||
*/
|
||
private FileDetailInfo readFileDetailInfo(Path filePath) throws IOException {
|
||
String fileName = filePath.getFileName().toString();
|
||
String fileContent = readFileContent(filePath);
|
||
long fileSize = Files.size(filePath);
|
||
|
||
LocalDateTime lastModified = LocalDateTime.ofInstant(
|
||
Files.getLastModifiedTime(filePath).toInstant(),
|
||
java.time.ZoneId.systemDefault()
|
||
);
|
||
String lastModifiedStr = lastModified.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||
|
||
return new FileDetailInfo(fileName, fileContent, fileSize, lastModifiedStr, filePath.toString());
|
||
}
|
||
|
||
/**
|
||
* 读取文件内容
|
||
*/
|
||
private String readFileContent(Path filePath) throws IOException {
|
||
try {
|
||
// 尝试使用UTF-8编码读取
|
||
return new String(Files.readAllBytes(filePath), "UTF-8");
|
||
} catch (Exception e) {
|
||
try {
|
||
// 如果UTF-8失败,尝试使用系统默认编码
|
||
return new String(Files.readAllBytes(filePath));
|
||
} catch (Exception e2) {
|
||
return "文件读取失败: " + e2.getMessage();
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取目录统计信息
|
||
* GET /wms/file/stats
|
||
*/
|
||
@GetMapping("/stats")
|
||
@ResponseBody
|
||
public ResponseEntity<ApiResponseVo<Map<String, Object>>> getDirectoryStats() {
|
||
try {
|
||
Path directory = Paths.get(directoryPath);
|
||
|
||
if (!Files.exists(directory)) {
|
||
return ResponseEntity.ok(new ApiResponseVo<>(false, "目录不存在: " + directoryPath, null));
|
||
}
|
||
|
||
Map<String, Object> stats = new HashMap<>();
|
||
int fileCount = 0;
|
||
long totalSize = 0;
|
||
List<String> fileNames = new ArrayList<>();
|
||
|
||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(directory)) {
|
||
for (Path file : stream) {
|
||
if (Files.isRegularFile(file)) {
|
||
fileCount++;
|
||
totalSize += Files.size(file);
|
||
fileNames.add(file.getFileName().toString());
|
||
}
|
||
}
|
||
}
|
||
|
||
stats.put("directoryPath", directoryPath);
|
||
stats.put("fileCount", fileCount);
|
||
stats.put("totalSize", totalSize);
|
||
stats.put("totalSizeMB", String.format("%.2f MB", totalSize / (1024.0 * 1024.0)));
|
||
stats.put("fileNames", fileNames);
|
||
stats.put("lastUpdated", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||
|
||
String message = String.format("目录统计: %d 个文件, 总大小 %.2f MB", fileCount, totalSize / (1024.0 * 1024.0));
|
||
return ResponseEntity.ok(new ApiResponseVo<>(true, message, stats));
|
||
|
||
} catch (Exception e) {
|
||
String errorMsg = "获取目录统计失败: " + e.getMessage();
|
||
System.err.println(errorMsg);
|
||
e.printStackTrace();
|
||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||
.body(new ApiResponseVo<>(false, errorMsg, null));
|
||
}
|
||
}
|
||
}
|