u
This commit is contained in:
1 parent
f9eaacf02a
commit
69eda8b8ad
27 files changed
+2797
-616
No files matched your search
@@ -19,14 +19,14 @@ public class FileConfig {
|
||||
private String staticPath;
|
||||
|
||||
public String getCommonPath() {
|
||||
return PathUtils.joinFilePath(commonDir, commonDir);
|
||||
return PathUtils.joinFilePath(baseDir, commonDir);
|
||||
}
|
||||
|
||||
public String getContainerPath() {
|
||||
return PathUtils.joinFilePath(commonDir, containerDir);
|
||||
return PathUtils.joinFilePath(baseDir, containerDir);
|
||||
}
|
||||
|
||||
public String getTempPath() {
|
||||
return PathUtils.joinFilePath(commonDir, tempDir);
|
||||
return PathUtils.joinFilePath(baseDir, tempDir);
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,6 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler(fileConfig.getStaticPath() + "/**")
|
||||
.addResourceLocations("file:" + fileConfig.getUploadDir() + "/");
|
||||
.addResourceLocations("file:" + fileConfig.getBaseDir() + "/");
|
||||
}
|
||||
}
|
||||
+152
-110
@@ -14,10 +14,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/file")
|
||||
@@ -25,8 +22,6 @@ public class FileController {
|
||||
@Resource
|
||||
private DbUtils dbUtils;
|
||||
@Resource
|
||||
private FileUploadUtils fileUploadUtils;
|
||||
@Resource
|
||||
private FileConfig fileConfig;
|
||||
|
||||
/**
|
||||
@@ -34,9 +29,9 @@ public class FileController {
|
||||
*/
|
||||
@PostMapping("/uploadTemp")
|
||||
public Result<Map<String, String>> uploadTemp(
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(value = "fileName", required = false) String fileName)
|
||||
throws Exception{
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(value = "fileName", required = false) String fileName)
|
||||
throws Exception {
|
||||
// 1. 校验
|
||||
FileUtils.checkFile(file);
|
||||
|
||||
@@ -46,6 +41,7 @@ public class FileController {
|
||||
// 3. 物理路径
|
||||
String basePath = fileConfig.getTempPath(); // D:/data/file/temp/
|
||||
|
||||
System.out.println(basePath);
|
||||
// 4. 保存
|
||||
FileUtils.saveFile(file, basePath, uuidName);
|
||||
|
||||
@@ -69,10 +65,7 @@ public class FileController {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Result<Map<String, Object>> uploadCommon(
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam("moduleId") String moduleId,
|
||||
@RequestParam("father") Long father,
|
||||
@RequestParam("fileName") String fileName,
|
||||
@RequestParam(value = "mxXh", required = false) Integer mxXh
|
||||
@RequestParam("fileName") String fileName
|
||||
) throws Exception {
|
||||
// 1. 校验
|
||||
FileUtils.checkFile(file);
|
||||
@@ -97,22 +90,6 @@ public class FileController {
|
||||
uuidName
|
||||
);
|
||||
|
||||
// 保存到数据库
|
||||
String fileSuffix = FileUtils.getSuffix(fileName);
|
||||
long fileSize = FileUtils.getFileSize(file);
|
||||
|
||||
Map<String, Object> insertMap = new HashMap<>();
|
||||
insertMap.put("subid", UniqueId.nextId());
|
||||
insertMap.put("father", father);
|
||||
insertMap.put("mx_moduleid", moduleId);
|
||||
insertMap.put("mx_xh", Optional.ofNullable(mxXh).orElse(0));
|
||||
insertMap.put("mx_filename", fileName);
|
||||
insertMap.put("mx_filesize", fileSize);
|
||||
insertMap.put("mx_fileext", fileSuffix);
|
||||
insertMap.put("mx_mapfilename", relativePath);
|
||||
|
||||
dbUtils.insert("bf_file", "subid", insertMap);
|
||||
|
||||
// 7. URL
|
||||
String url = PathUtils.joinUrl(
|
||||
fileConfig.getServerUrl(),
|
||||
@@ -129,127 +106,192 @@ public class FileController {
|
||||
return Result.ok(result);
|
||||
}
|
||||
|
||||
// @PostMapping("/uploadContainer")
|
||||
// @Transactional(rollbackFor = Exception.class)
|
||||
// public Result<Map<String, Object>> uploadContainer(
|
||||
// @RequestParam("file") MultipartFile file,
|
||||
// @RequestParam("containerNo") String containerNo,
|
||||
// @RequestParam("fileName") String fileName,
|
||||
// @RequestParam("jobId") String jobId
|
||||
// ) throws Exception {
|
||||
// // 1. 校验
|
||||
// FileUtils.checkFile(file);
|
||||
//
|
||||
// // 2. 日期路径
|
||||
// String datePath = TimeUtils.todayPath(); // 2026/03/30/
|
||||
//
|
||||
// // 3. 根路径
|
||||
// String basePath = fileConfig.getContainerPath();
|
||||
//
|
||||
// // 4. 构建目录:日期 / 箱号 / jobId
|
||||
// String fullDirPath = PathUtils.joinFilePath(
|
||||
// basePath,
|
||||
// datePath,
|
||||
// containerNo,
|
||||
// jobId
|
||||
// );
|
||||
//
|
||||
// // 5. 创建目录(幂等)
|
||||
// File dir = new File(fullDirPath);
|
||||
// if (!dir.exists()) {
|
||||
// dir.mkdirs();
|
||||
// }
|
||||
//
|
||||
// // 6. 文件后缀
|
||||
// String suffix = FileUtils.getSuffix(fileName);
|
||||
//
|
||||
// long nextId = UniqueId.nextId();
|
||||
//
|
||||
// // 7. 使用雪花ID作为文件名(核心优化)
|
||||
// String newFileName = nextId + suffix;
|
||||
//
|
||||
// // 8. 保存文件
|
||||
// FileUtils.saveFile(file, fullDirPath, newFileName);
|
||||
//
|
||||
// // 9. 相对路径
|
||||
// String relativePath = PathUtils.joinFilePath(
|
||||
// fileConfig.getContainerDir(),
|
||||
// datePath,
|
||||
// containerNo,
|
||||
// jobId,
|
||||
// newFileName
|
||||
// );
|
||||
//
|
||||
// // 10. URL
|
||||
// String url = PathUtils.joinUrl(
|
||||
// fileConfig.getServerUrl(),
|
||||
// fileConfig.getStaticPath(),
|
||||
// relativePath
|
||||
// );
|
||||
//
|
||||
// // 11. 返回
|
||||
// Map<String, Object> result = new HashMap<>();
|
||||
// result.put("url", url);
|
||||
// result.put("path", relativePath);
|
||||
// result.put("uid", nextId);
|
||||
// result.put("fileName", newFileName);
|
||||
//
|
||||
// return Result.ok(result);
|
||||
// }
|
||||
|
||||
@PostMapping("/uploadContainer")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Result<Map<String, Object>> uploadContainer(
|
||||
@RequestParam("file") MultipartFile file,
|
||||
@RequestParam("containerNo") String containerNo
|
||||
@RequestParam("fileName") String fileName
|
||||
) throws Exception {
|
||||
|
||||
// 1. 校验
|
||||
FileUtils.checkFile(file);
|
||||
|
||||
// 2. 日期路径
|
||||
String datePath = TimeUtils.todayPath(); // 2026/03/29/
|
||||
String datePath = TimeUtils.todayPath(); // 2026/03/30/
|
||||
|
||||
// 3. 根路径
|
||||
String basePath = fileConfig.getContainerPath();
|
||||
String dayPath = PathUtils.joinFilePath(basePath, datePath);
|
||||
|
||||
String relativePath;
|
||||
String fileName;
|
||||
String containerDirName;
|
||||
// 4. 雪花 ID(唯一)
|
||||
long nextId = UniqueId.nextId();
|
||||
|
||||
// 🔥 4. 并发锁(同一天 + container)
|
||||
String lockKey = (datePath + containerNo).intern();
|
||||
// 5. 分桶(0-ff)
|
||||
String bucket = String.format("%02x", nextId & 0xff);
|
||||
|
||||
synchronized (lockKey) {
|
||||
// 6. 构建目录:日期 + 分桶
|
||||
String fullDirPath = PathUtils.joinFilePath(
|
||||
basePath,
|
||||
datePath,
|
||||
bucket
|
||||
);
|
||||
|
||||
// 4.1 获取 container 目录(防重复)
|
||||
containerDirName = getAvailableContainerDir(dayPath, containerNo);
|
||||
|
||||
String fullDirPath = PathUtils.joinFilePath(dayPath, containerDirName);
|
||||
|
||||
// 4.2 获取下一个序号(不补位)
|
||||
int index = getNextIndex(fullDirPath);
|
||||
|
||||
// 4.3 后缀
|
||||
String suffix = FileUtils.getSuffix(file.getOriginalFilename());
|
||||
|
||||
// 4.4 文件名(核心规则)
|
||||
fileName = containerNo + "_" + String.format("%02d", index) + suffix;
|
||||
|
||||
// 4.5 保存
|
||||
FileUtils.saveFile(file, fullDirPath, fileName);
|
||||
|
||||
// 4.6 相对路径
|
||||
relativePath = PathUtils.joinFilePath(
|
||||
fileConfig.getContainerDir(),
|
||||
datePath,
|
||||
containerDirName,
|
||||
fileName
|
||||
);
|
||||
// 7. 创建目录(幂等)
|
||||
File dir = new File(fullDirPath);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
// 5. URL
|
||||
// 8. 文件后缀
|
||||
String suffix = FileUtils.getSuffix(fileName);
|
||||
|
||||
String newFileName = nextId + suffix;
|
||||
|
||||
// 9. 保存文件
|
||||
FileUtils.saveFile(file, fullDirPath, newFileName);
|
||||
|
||||
// 10. 相对路径
|
||||
String relativePath = PathUtils.joinFilePath(
|
||||
fileConfig.getContainerDir(),
|
||||
datePath,
|
||||
bucket,
|
||||
newFileName
|
||||
);
|
||||
|
||||
// 11. URL
|
||||
String url = PathUtils.joinUrl(
|
||||
fileConfig.getServerUrl(),
|
||||
fileConfig.getStaticPath(),
|
||||
relativePath
|
||||
);
|
||||
|
||||
// 6. 返回
|
||||
// 12. 返回
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("url", url);
|
||||
result.put("path", relativePath);
|
||||
result.put("fileName", fileName);
|
||||
result.put("containerDir", containerDirName);
|
||||
result.put("uid", nextId);
|
||||
result.put("fileName", newFileName);
|
||||
result.put("bucket", bucket);
|
||||
|
||||
return Result.ok(result);
|
||||
}
|
||||
|
||||
public static int getNextIndex(String dirPath) {
|
||||
File dir = new File(dirPath);
|
||||
@PostMapping("/delete")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Result<Void> deleteFile(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
// 1. 参数校验
|
||||
ValidationUtils.checkRequiredFields(params, "subid");
|
||||
|
||||
if (!dir.exists()) {
|
||||
return 1;
|
||||
}
|
||||
Long subid = Long.valueOf(params.get("subid").toString());
|
||||
|
||||
File[] files = dir.listFiles();
|
||||
if (files == null || files.length == 0) {
|
||||
return 1;
|
||||
}
|
||||
// 2. 查询文件记录
|
||||
List<Map<String, Object>> maps = dbUtils.loadData(
|
||||
"SELECT * FROM bf_file WHERE subid = ?", subid
|
||||
);
|
||||
|
||||
int max = 0;
|
||||
|
||||
for (File f : files) {
|
||||
String name = f.getName();
|
||||
|
||||
// 解析 xxx_01.jpg
|
||||
int underscore = name.lastIndexOf("_");
|
||||
int dot = name.lastIndexOf(".");
|
||||
|
||||
if (underscore > -1 && dot > underscore) {
|
||||
try {
|
||||
int num = Integer.parseInt(name.substring(underscore + 1, dot));
|
||||
max = Math.max(max, num);
|
||||
} catch (Exception ignored) {}
|
||||
if (maps.isEmpty()) {
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
|
||||
return max + 1;
|
||||
}
|
||||
Map<String, Object> objectMap = maps.get(0);
|
||||
|
||||
public static String getAvailableContainerDir(String basePath, String containerNo) {
|
||||
File baseDir = new File(basePath);
|
||||
// 3. 获取文件路径
|
||||
String mxMapfilename = objectMap.get("mx_mapfilename") == null
|
||||
? ""
|
||||
: objectMap.get("mx_mapfilename").toString();
|
||||
|
||||
if (!baseDir.exists()) {
|
||||
baseDir.mkdirs();
|
||||
}
|
||||
|
||||
File dir = new File(baseDir, containerNo);
|
||||
if (!dir.exists()) {
|
||||
return containerNo;
|
||||
}
|
||||
|
||||
int i = 1;
|
||||
while (true) {
|
||||
String newName = containerNo + "_" + String.format("%02d", i);
|
||||
File newDir = new File(baseDir, newName);
|
||||
if (!newDir.exists()) {
|
||||
return newName;
|
||||
if (StringUtils.isBlank(mxMapfilename)) {
|
||||
return Result.fail("文件路径为空");
|
||||
}
|
||||
i++;
|
||||
|
||||
// 4. 拼接真实路径
|
||||
String filePath = PathUtils.joinFilePath(
|
||||
fileConfig.getBaseDir(),
|
||||
mxMapfilename
|
||||
);
|
||||
|
||||
// 5. 删除本地文件
|
||||
boolean deleted = FileUtils.deleteFileByPath(filePath);
|
||||
if (!deleted) {
|
||||
System.out.println("文件删除失败或不存在: " + filePath);
|
||||
}
|
||||
|
||||
// 6. 删除数据库
|
||||
dbUtils.deleteById("bf_file", "subid", subid);
|
||||
|
||||
return Result.ok();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return Result.fail("删除失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -68,6 +68,7 @@ public class OcrController {
|
||||
|
||||
return Result.ok(result);
|
||||
} catch (Exception e){
|
||||
e.printStackTrace();
|
||||
return Result.fail("OCR 识别失败,请联系管理员");
|
||||
}
|
||||
}
|
||||
|
||||
+63
-52
@@ -41,67 +41,78 @@ public class OssController {
|
||||
ValidationUtils.checkRequiredFields(params, "father", "mx_xh", "mx_filename", "mx_filesize", "mx_mapfilename", "mx_moduleid");
|
||||
|
||||
String userId = UserContext.get().getUserId();
|
||||
Object subIdObj = params.get("subid");
|
||||
|
||||
long nextId = UniqueId.nextId();
|
||||
Long subid = null;
|
||||
|
||||
params.put("subid", nextId);
|
||||
if (subIdObj != null) {
|
||||
subid = Long.valueOf(subIdObj.toString());
|
||||
}
|
||||
|
||||
// 如果 subid 为空,生成新ID
|
||||
if (subid == null) {
|
||||
long nextId = UniqueId.nextId();
|
||||
subid = nextId;
|
||||
}
|
||||
|
||||
params.put("subid", subid);
|
||||
params.put("mx_inputuser_id",userId);
|
||||
params.put("mx_inputdatetime", TimeUtils.getDateTime());
|
||||
|
||||
dbUtils.insert("bf_file","subid",params);
|
||||
|
||||
return Result.ok(nextId);
|
||||
return Result.ok(subid);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Result<Void> deleteFile(@RequestBody Map<String, Object> params) {
|
||||
ValidationUtils.checkRequiredFields(params, "subid", "tableName", "bucketName");
|
||||
|
||||
String tableName = params.get("tableName").toString();
|
||||
String bucketName = params.get("bucketName").toString();
|
||||
String id = params.get("subid").toString();
|
||||
|
||||
// 查询数据
|
||||
List<Map<String, Object>> maps = dbUtils.loadData("SELECT * FROM " + tableName + " WHERE subid = ?", id);
|
||||
|
||||
// 如果没有数据,直接返回删除成功
|
||||
if (ObjectUtils.isEmpty(maps)) {
|
||||
return Result.ok("删除成功");
|
||||
}
|
||||
|
||||
String mxMapfilename = maps.get(0).get("mx_mapfilename").toString();
|
||||
String orgId = UserContext.get().getOrgId();
|
||||
int index = mxMapfilename.indexOf(orgId + "/");
|
||||
|
||||
// 如果没找到,就转换orgId为大写
|
||||
if (index < 0) {
|
||||
orgId = orgId.toUpperCase();
|
||||
index = mxMapfilename.indexOf(orgId + "/");
|
||||
}
|
||||
|
||||
String objectName = mxMapfilename.substring(index);
|
||||
|
||||
// 删除记录
|
||||
Map<String, Object> deleteParams = new HashMap<>();
|
||||
deleteParams.put("subid", id);
|
||||
int deleteCount = dbUtils.delete(tableName, deleteParams);
|
||||
|
||||
// 如果删除成功,发送删除请求
|
||||
if (deleteCount > 0) {
|
||||
if(StringUtils.isBlank(objectName)){
|
||||
return Result.fail("删除失败,文件格式有误");
|
||||
}
|
||||
String requestUrl = String.format("http://g3oss.g3soft.cn:8082/delete?bucketName=%s&objectName=%s", bucketName, objectName);
|
||||
try {
|
||||
HttpUtils.get(requestUrl);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("删除文件失败",e);
|
||||
}
|
||||
}
|
||||
|
||||
return Result.ok();
|
||||
}
|
||||
// @PostMapping("/delete")
|
||||
// @Transactional(rollbackFor = Exception.class)
|
||||
// public Result<Void> deleteFile(@RequestBody Map<String, Object> params) {
|
||||
// ValidationUtils.checkRequiredFields(params, "subid", "tableName", "bucketName");
|
||||
//
|
||||
// String tableName = params.get("tableName").toString();
|
||||
// String bucketName = params.get("bucketName").toString();
|
||||
// String id = params.get("subid").toString();
|
||||
//
|
||||
// // 查询数据
|
||||
// List<Map<String, Object>> maps = dbUtils.loadData("SELECT * FROM " + tableName + " WHERE subid = ?", id);
|
||||
//
|
||||
// // 如果没有数据,直接返回删除成功
|
||||
// if (ObjectUtils.isEmpty(maps)) {
|
||||
// return Result.ok("删除成功");
|
||||
// }
|
||||
//
|
||||
// String mxMapfilename = maps.get(0).get("mx_mapfilename").toString();
|
||||
// String orgId = UserContext.get().getOrgId();
|
||||
// int index = mxMapfilename.indexOf(orgId + "/");
|
||||
//
|
||||
// // 如果没找到,就转换orgId为大写
|
||||
// if (index < 0) {
|
||||
// orgId = orgId.toUpperCase();
|
||||
// index = mxMapfilename.indexOf(orgId + "/");
|
||||
// }
|
||||
//
|
||||
// String objectName = mxMapfilename.substring(index);
|
||||
//
|
||||
// // 删除记录
|
||||
// Map<String, Object> deleteParams = new HashMap<>();
|
||||
// deleteParams.put("subid", id);
|
||||
// int deleteCount = dbUtils.delete(tableName, deleteParams);
|
||||
//
|
||||
// // 如果删除成功,发送删除请求
|
||||
// if (deleteCount > 0) {
|
||||
// if(StringUtils.isBlank(objectName)){
|
||||
// return Result.fail("删除失败,文件格式有误");
|
||||
// }
|
||||
// String requestUrl = String.format("http://g3oss.g3soft.cn:8082/delete?bucketName=%s&objectName=%s", bucketName, objectName);
|
||||
// try {
|
||||
// HttpUtils.get(requestUrl);
|
||||
// } catch (Exception e) {
|
||||
// throw new RuntimeException("删除文件失败",e);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return Result.ok();
|
||||
// }
|
||||
|
||||
@PostMapping("/deleteAliyunFile")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
|
||||
-99
@@ -1,99 +0,0 @@
|
||||
package cn.g3soft.utils;
|
||||
|
||||
import cn.g3soft.config.FileConfig;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通用文件上传工具类
|
||||
* 规则:
|
||||
* - 文件名保持原始或指定
|
||||
* - 同一天同箱号重复 -> 自动生成 _1/_2/... 文件夹
|
||||
* - 使用 FileUtils 拼接路径
|
||||
*/
|
||||
@Component
|
||||
public class FileContainerUtils {
|
||||
|
||||
@Resource
|
||||
private FileConfig fileConfig;
|
||||
|
||||
/**
|
||||
* 单文件上传
|
||||
*/
|
||||
public String upload(MultipartFile file, String containerNo, String fileName) throws IOException {
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new RuntimeException("文件不能为空");
|
||||
}
|
||||
|
||||
// 1. 日期路径 yyyy/MM/dd
|
||||
String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
|
||||
|
||||
// 2. 基础目录:上传目录 + 日期
|
||||
String basePath = PathUtils.joinFilePath(fileConfig.getContainerPath(), datePath);
|
||||
|
||||
// 3. 计算最终目录(箱号 + 重复批次)
|
||||
File finalDir = resolveContainerDir(basePath, containerNo);
|
||||
|
||||
if (!finalDir.exists()) {
|
||||
finalDir.mkdirs();
|
||||
}
|
||||
|
||||
// 4. 最终文件
|
||||
File dest = new File(finalDir, fileName);
|
||||
file.transferTo(dest);
|
||||
|
||||
// 5. 相对路径,用于生成URL
|
||||
String relativePath = PathUtils.joinFilePath(
|
||||
datePath,
|
||||
finalDir.getName(),
|
||||
fileName
|
||||
);
|
||||
|
||||
return fileConfig.buildFileUrl(relativePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 多文件上传
|
||||
*/
|
||||
public List<String> uploadBatch(MultipartFile[] files, String containerNo, String[] fileNames) throws IOException {
|
||||
if (files == null || files.length == 0) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<String> urls = new ArrayList<>();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
String name = (fileNames != null && i < fileNames.length) ? fileNames[i] : files[i].getOriginalFilename();
|
||||
urls.add(upload(files[i], containerNo, name));
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析容器目录
|
||||
* - 如果同一天已存在该箱号目录 -> 自动加 _1/_2/... 避免覆盖
|
||||
*/
|
||||
private File resolveContainerDir(String basePath, String containerNo) {
|
||||
File containerDir = new File(PathUtils.joinFilePath(basePath, containerNo));
|
||||
|
||||
if (!containerDir.exists()) {
|
||||
return containerDir;
|
||||
}
|
||||
|
||||
// 已存在 -> 找下一个可用序号
|
||||
int i = 1;
|
||||
while (true) {
|
||||
File dir = new File(PathUtils.joinFilePath(basePath, containerNo + "_" + i));
|
||||
if (!dir.exists()) {
|
||||
return dir;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package cn.g3soft.utils;
|
||||
|
||||
import cn.g3soft.config.FileConfig;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.UUID;
|
||||
|
||||
@Component
|
||||
public class FileUploadUtils {
|
||||
|
||||
@Resource
|
||||
private FileConfig fileConfig;
|
||||
|
||||
/**
|
||||
* 上传文件到临时路径
|
||||
* @param file 上传的文件
|
||||
* @param fileName 如果前端传递了文件名,使用传递的文件名
|
||||
* @return 临时文件的URL
|
||||
*/
|
||||
public String uploadTemp(MultipartFile file, String fileName) throws IOException {
|
||||
// 1. 生成最终文件名
|
||||
String finalFileName = generateTempFileName(file, fileName);
|
||||
|
||||
// 2. 临时目录路径
|
||||
File tempDir = new File(fileConfig.getTempPath());
|
||||
|
||||
// 如果临时目录不存在,创建目录
|
||||
if (!tempDir.exists()) {
|
||||
tempDir.mkdirs();
|
||||
}
|
||||
|
||||
// 3. 保存文件到临时目录
|
||||
File tempFile = new File(tempDir, finalFileName);
|
||||
file.transferTo(tempFile);
|
||||
|
||||
// 4. 返回临时文件的 URL(供 OCR 使用)
|
||||
return fileConfig.buildTempUrl(finalFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件名生成临时文件名(带时间戳 + UUID + 文件后缀)
|
||||
* @param file 上传的文件
|
||||
* @param fileName 传递的文件名(可选)
|
||||
* @return 生成的最终文件名
|
||||
*/
|
||||
private String generateTempFileName(MultipartFile file, String fileName) {
|
||||
// 优先使用前端传递的 fileName
|
||||
String originalFilename = (fileName != null && !fileName.isEmpty())
|
||||
? fileName
|
||||
: file.getOriginalFilename();
|
||||
|
||||
// 如果没有获取到文件名,设置一个默认文件名
|
||||
if (originalFilename == null) {
|
||||
originalFilename = "file";
|
||||
}
|
||||
|
||||
// 获取文件后缀
|
||||
String extension = "";
|
||||
if (originalFilename.contains(".")) {
|
||||
extension = originalFilename.substring(originalFilename.lastIndexOf("."));
|
||||
}
|
||||
|
||||
// 生成带时间戳和 UUID 的文件名
|
||||
return LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE) + "_"
|
||||
+ UUID.randomUUID().toString().replace("-", "") + extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除临时文件(成功识别后删除)
|
||||
* @param tempFileName 临时文件的文件名
|
||||
*/
|
||||
public void deleteTempFile(String tempFileName) {
|
||||
String filePath = PathUtils.joinFilePath(fileConfig.getBaseDir(), fileConfig.getTempDir(), tempFileName);
|
||||
|
||||
File tempFile = new File(tempFileName);
|
||||
if (tempFile.exists()) {
|
||||
tempFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -114,4 +114,63 @@ public class FileUtils {
|
||||
throw new RuntimeException("上传文件不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean deleteFileByPath(String fullPath) {
|
||||
if (fullPath == null || fullPath.trim().isEmpty()) {
|
||||
throw new RuntimeException("路径不能为空");
|
||||
}
|
||||
|
||||
File file = new File(fullPath);
|
||||
|
||||
// 防止误删
|
||||
if (!file.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file.isFile()) {
|
||||
throw new RuntimeException("不是文件: " + fullPath);
|
||||
}
|
||||
|
||||
return file.delete();
|
||||
}
|
||||
|
||||
public static boolean deleteDirectory(String dirPath) {
|
||||
if (dirPath == null || dirPath.trim().isEmpty()) {
|
||||
throw new RuntimeException("路径不能为空");
|
||||
}
|
||||
|
||||
File dir = new File(dirPath);
|
||||
|
||||
if (!dir.exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dir.isDirectory()) {
|
||||
throw new RuntimeException("不是文件夹: " + dirPath);
|
||||
}
|
||||
|
||||
return deleteDirRecursively(dir);
|
||||
}
|
||||
|
||||
private static boolean deleteDirRecursively(File dir) {
|
||||
File[] files = dir.listFiles();
|
||||
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
// 递归删除子目录
|
||||
deleteDirRecursively(file);
|
||||
} else {
|
||||
// 删除文件
|
||||
if (!file.delete()) {
|
||||
throw new RuntimeException("文件删除失败: " + file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除当前目录
|
||||
return dir.delete();
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,9 @@ public class PathUtils {
|
||||
|
||||
part = part.trim();
|
||||
|
||||
// 替换 Windows 路径分隔符为 URL 的 '/'
|
||||
part = part.replace("\\", "/");
|
||||
|
||||
if (sb.length() == 0) {
|
||||
// 第一段:保留协议(http://)
|
||||
sb.append(part.replaceAll("/+$", ""));
|
||||
|
||||
Reference in new issue
Block a user