feat: 增强文件上传控制器功能

完善文件上传相关的控制器模块:
- FileController: 通用文件上传控制器
- SysFileController: 系统文件管理控制器
- SysPictureController: 系统图片管理控制器

集成OSS存储服务,支持多种存储方式,
提供统一的文件上传、下载和管理接口。
This commit is contained in:
Leo 2025-07-09 14:44:07 +08:00
parent a810edb0bc
commit b2ea8a3906
3 changed files with 69 additions and 46 deletions

View File

@ -79,16 +79,24 @@ public class FileController {
*/ */
@Operation(summary = "上传文件", description = "上传单个文件到服务器") @Operation(summary = "上传文件", description = "上传单个文件到服务器")
@PostMapping("/file/uploadFile/{fileSize}/{folderName}/{fileParam}") @PostMapping("/file/uploadFile/{fileSize}/{folderName}/{fileParam}")
public Map<String, Object> uploadSingleFile(@RequestParam("file") MultipartFile file, @PathVariable("fileSize") Integer fileSize, @PathVariable("folderName") String folderName, @PathVariable("fileParam") String fileParam) { public Map<String, Object> uploadSingleFile(
@RequestParam("file") MultipartFile file,
@PathVariable("fileSize") Integer fileSize,
@PathVariable("folderName") String folderName,
@PathVariable("fileParam") String fileParam,
@RequestParam(value = "storageType", required = false) String requestStorageType) {
// 文件预检查 // 文件预检查
validateUploadFile(file, fileSize, folderName); validateUploadFile(file, fileSize, folderName);
// 确定要使用的存储类型
String requestedStorageType = determineStorageType(requestStorageType);
Map<String, Object> fileMap; Map<String, Object> fileMap;
try { try {
// 根据配置选择存储服务 // 根据确定的存储类型选择存储服务
StorageService storageService = storageServiceFactory.getStorageService(storageType); StorageService storageService = storageServiceFactory.getStorageService(requestedStorageType);
// 生成唯一文件名 // 生成唯一文件名
String fileName = OssUtil.generateUniqueFileName(file.getOriginalFilename()); String fileName = OssUtil.generateUniqueFileName(file.getOriginalFilename());
@ -99,11 +107,10 @@ public class FileController {
// 上传文件 // 上传文件
fileMap = storageService.uploadFile(file, fileName, folderPath); fileMap = storageService.uploadFile(file, fileName, folderPath);
log.info("文件上传成功: storageType={}, fileName={}, filePath={}", log.info("文件上传成功: requestedStorageType={}, fileName={}, filePath={}",
storageType, fileName, fileMap.get("filePath")); requestedStorageType, fileName, fileMap.get("filePath"));
} catch (Exception e) { } catch (Exception e) {
log.error("文件上传失败,尝试使用本地存储降级", e);
// 降级到本地存储 // 降级到本地存储
try { try {
@ -172,6 +179,7 @@ public class FileController {
} else { } else {
sysPicture.setPictureType(fileParam); sysPicture.setPictureType(fileParam);
} }
if (isCreateBy) { if (isCreateBy) {
sysPicture.setCreateBy(CoderLoginUtil.getUserName()); sysPicture.setCreateBy(CoderLoginUtil.getUserName());
} }
@ -179,21 +187,18 @@ public class FileController {
} }
/** /**
* @description [保存上传文件信息] * 保存文件信息到数据库
* @author Leocoder
*/ */
private void saveUploadFilesInformation(Map<String, Object> fileMap, String storageServiceType, boolean isCreateBy) { private void saveUploadFilesInformation(Map<String, Object> fileMap, String storageType, Boolean isCreateBy) {
log.info("文件上传 ->");
// 新增文件信息
SysFile sysFile = new SysFile(); SysFile sysFile = new SysFile();
sysFile.setFileName(fileMap.get("fileName").toString()); sysFile.setFileName(fileMap.get("fileName").toString());
sysFile.setNewName(fileMap.get("newName").toString()); sysFile.setNewName(fileMap.get("newName").toString());
sysFile.setFileSize(fileMap.get("fileSize").toString()); sysFile.setFileSize(fileMap.get("fileSize").toString());
sysFile.setFileSuffix(fileMap.get("suffixName").toString()); sysFile.setFileSuffix(fileMap.get("suffixName").toString());
sysFile.setFileUpload(fileMap.get("filePath").toString()); sysFile.setFileUpload(fileMap.get("filePath").toString());
sysFile.setFileService(storageServiceType); sysFile.setFileService(storageType);
// 设置文件访问路径 // 判断是否为完整URL如OSS存储
String fileUploadPath = (String) fileMap.get("fileUploadPath"); String fileUploadPath = (String) fileMap.get("fileUploadPath");
if (isFullUrl(fileUploadPath)) { if (isFullUrl(fileUploadPath)) {
// 如果已经是完整URL如OSS直接使用 // 如果已经是完整URL如OSS直接使用
@ -226,6 +231,30 @@ public class FileController {
return StringUtils.isNotBlank(url) && (url.startsWith("http://") || url.startsWith("https://")); return StringUtils.isNotBlank(url) && (url.startsWith("http://") || url.startsWith("https://"));
} }
/**
* 确定要使用的存储类型
*/
private String determineStorageType(String requestStorageType) {
// 如果前端传递了存储类型优先使用前端选择的类型
if (StringUtils.isNotBlank(requestStorageType)) {
String normalizedType = requestStorageType.trim().toUpperCase();
// 将前端选择的类型转换为实际的存储服务类型
switch (normalizedType) {
case "LOCAL":
return "local";
case "OSS":
return "oss";
default:
log.warn("未知的存储类型: {}, 使用默认配置", requestStorageType);
break;
}
}
// 如果前端没有传递存储类型或类型无效使用配置文件中的默认值
return storageType;
}
/** /**
* 确定实际使用的存储服务类型 * 确定实际使用的存储服务类型
*/ */
@ -236,14 +265,14 @@ public class FileController {
if (isFullUrl(fileUploadPath)) { if (isFullUrl(fileUploadPath)) {
// 如果是完整URL检查是否包含OSS域名 // 如果是完整URL检查是否包含OSS域名
if (fileUploadPath.contains(".aliyuncs.com") || fileUploadPath.contains("oss-")) { if (fileUploadPath.contains(".aliyuncs.com") || fileUploadPath.contains("oss-")) {
return "3"; // OSS // OSS
} else if (fileUploadPath.contains("minio") || fileUploadPath.contains(":9000")) { return "3";
return "2"; // MinIO
} }
} }
// 默认为本地存储 // 默认为本地存储
return "1"; // Local // Local
return "1";
} }
/** /**
@ -255,16 +284,24 @@ public class FileController {
@Operation(summary = "匿名上传文件", description = "匿名上传单个文件到服务器,无需登录认证") @Operation(summary = "匿名上传文件", description = "匿名上传单个文件到服务器,无需登录认证")
@SaIgnore @SaIgnore
@PostMapping("/file/uploadAnyFile/{fileSize}/{folderName}/{fileParam}") @PostMapping("/file/uploadAnyFile/{fileSize}/{folderName}/{fileParam}")
public Map<String, Object> uploadAnyFile(@RequestParam("file") MultipartFile file, @PathVariable("fileSize") Integer fileSize, @PathVariable("folderName") String folderName, @PathVariable("fileParam") String fileParam) { public Map<String, Object> uploadAnyFile(
@RequestParam("file") MultipartFile file,
@PathVariable("fileSize") Integer fileSize,
@PathVariable("folderName") String folderName,
@PathVariable("fileParam") String fileParam,
@RequestParam(value = "storageType", required = false) String requestStorageType) {
// 文件预检查 // 文件预检查
validateUploadFile(file, fileSize, folderName); validateUploadFile(file, fileSize, folderName);
// 确定要使用的存储类型
String requestedStorageType = determineStorageType(requestStorageType);
Map<String, Object> fileMap; Map<String, Object> fileMap;
try { try {
// 根据配置选择存储服务 // 根据确定的存储类型选择存储服务
StorageService storageService = storageServiceFactory.getStorageService(storageType); StorageService storageService = storageServiceFactory.getStorageService(requestedStorageType);
// 生成唯一文件名 // 生成唯一文件名
String fileName = OssUtil.generateUniqueFileName(file.getOriginalFilename()); String fileName = OssUtil.generateUniqueFileName(file.getOriginalFilename());
@ -275,8 +312,8 @@ public class FileController {
// 上传文件 // 上传文件
fileMap = storageService.uploadFile(file, fileName, folderPath); fileMap = storageService.uploadFile(file, fileName, folderPath);
log.info("匿名文件上传成功: storageType={}, fileName={}, filePath={}", log.info("匿名文件上传成功: requestedStorageType={}, fileName={}, filePath={}",
storageType, fileName, fileMap.get("filePath")); requestedStorageType, fileName, fileMap.get("filePath"));
} catch (Exception e) { } catch (Exception e) {
log.error("匿名文件上传失败,尝试使用本地存储降级", e); log.error("匿名文件上传失败,尝试使用本地存储降级", e);

View File

@ -169,19 +169,12 @@ public class SysFileController {
boolean deleteResult = false; boolean deleteResult = false;
switch (fileService) { switch (fileService) {
case "1": // 本地存储 // 本地存储
case "1":
deleteResult = FileUtil.deleteFile(filePath); deleteResult = FileUtil.deleteFile(filePath);
break; break;
case "2": // MinIO存储 // OSS存储
try { case "3":
StorageService minioService = storageServiceFactory.getStorageService("minio");
deleteResult = minioService.deleteFile(filePath);
} catch (Exception e) {
log.error("MinIO存储服务不可用尝试本地删除", e);
deleteResult = FileUtil.deleteFile(filePath);
}
break;
case "3": // OSS存储
try { try {
StorageService ossService = storageServiceFactory.getStorageService("oss"); StorageService ossService = storageServiceFactory.getStorageService("oss");
deleteResult = ossService.deleteFile(filePath); deleteResult = ossService.deleteFile(filePath);

View File

@ -162,20 +162,13 @@ public class SysPictureController {
boolean deleteResult = false; boolean deleteResult = false;
switch (fileService) { switch (fileService) {
case "1": // 本地存储 // 本地存储
case "1":
// 对于本地存储需要使用完整路径 // 对于本地存储需要使用完整路径
deleteResult = new java.io.File(filePath).delete(); deleteResult = new java.io.File(filePath).delete();
break; break;
case "2": // MinIO存储 // OSS存储
try { case "3":
StorageService minioService = storageServiceFactory.getStorageService("minio");
deleteResult = minioService.deleteFile(filePath);
} catch (Exception e) {
log.error("MinIO存储服务不可用跳过删除", e);
deleteResult = false;
}
break;
case "3": // OSS存储
try { try {
StorageService ossService = storageServiceFactory.getStorageService("oss"); StorageService ossService = storageServiceFactory.getStorageService("oss");
deleteResult = ossService.deleteFile(filePath); deleteResult = ossService.deleteFile(filePath);