package com.hotent.util; import com.hotent.baseInfo.vo.FileUploadResult; import com.hotent.config.EipConfig; import com.hotent.constant.BaseConstant; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; @Slf4j public class FileUploadUtil { // 允许上传的文件类型 private static final Set ALLOWED_EXTENSIONS = new HashSet<>(Arrays.asList( // 文档格式 "doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf", "txt", // 图片格式 "jpg", "jpeg", "png", "gif", "bmp", "webp", // 压缩包格式 "zip", "rar", "7z", // 其他常用格式 "csv", "xml", "json" )); // 文件大小限制 (单位: 字节,默认100MB) private static long MAX_FILE_SIZE = 100 * 1024 * 1024; /** * 单文件上传 * @param file 上传的文件 * @param businessFolder 业务文件夹名称 * @param baseUploadPath 基础上传路径 * @return 文件上传结果 */ public static FileUploadResult uploadFile(MultipartFile file, String baseUploadPath) { return uploadFiles(Collections.singletonList(file), baseUploadPath).get(0); } /** * 多文件上传 * @param files 上传的文件列表 * @param 业务文件夹名称 * @param baseUploadPath 基础上传路径 * @return 文件上传结果列表 */ public static List uploadFiles(List files, String baseUploadPath) { List results = new ArrayList<>(); for (MultipartFile file : files) { FileUploadResult result = new FileUploadResult(); result.setOriginalFilename(file.getOriginalFilename()); try { // 验证文件 validateFile(file); // 生成文件保存路径 String fileExtension = getFileExtension(file.getOriginalFilename()); String fileName = generateFileName(file.getOriginalFilename()); String savePath = generateSavePath(baseUploadPath, fileName, fileExtension); // 创建目录 createDirectories(savePath); log.info(savePath); // 保存文件 File destFile = new File(savePath); file.transferTo(destFile); // 设置成功结果 result.setFileName(fileName); result.setFileExtension(fileExtension); result.setSavePath(getPathFileName(savePath,fileName)); result.setFileSize(file.getSize()); result.setMessage("上传成功"); } catch (Exception e) { result.setMessage("上传失败: " + e.getMessage()); } results.add(result); } return results; } public static final String getPathFileName(String uploadDir, String fileName) { int dirLastIndex = EipConfig.getProfile().length() + 1; String currentDir = StringUtils.substring(uploadDir, dirLastIndex); return BaseConstant.RESOURCE_PREFIX + "/" + currentDir; } /** * 验证文件合法性 * @param file 文件 * @throws Exception 验证异常 */ private static void validateFile(MultipartFile file) throws Exception { // 检查文件是否为空 if (file.isEmpty()) { throw new Exception("文件为空"); } // 检查文件大小 if (file.getSize() > MAX_FILE_SIZE) { throw new Exception("文件大小超过限制(" + MAX_FILE_SIZE / (1024 * 1024) + "MB)"); } // 检查文件类型 String extension = getFileExtension(file.getOriginalFilename()); if (!ALLOWED_EXTENSIONS.contains(extension.toLowerCase())) { throw new Exception("不支持的文件类型: " + extension); } } public static String getFileType(String fileName) { int separatorIndex = fileName.lastIndexOf("."); if (separatorIndex < 0) { return ""; } return fileName.substring(separatorIndex + 1).toLowerCase(); } public static boolean checkAllowDownload(String resource) { // 禁止目录上跳级别 if (StringUtils.contains(resource, "..")) { return false; } if (ALLOWED_EXTENSIONS.contains(resource)) { return true; } // 不在允许下载的文件规则 return false; } /** * 获取文件扩展名 * @param fileName 文件名 * @return 文件扩展名 */ public static String getFileExtension(String fileName) { if (fileName == null || fileName.lastIndexOf(".") == -1) { return ""; } return fileName.substring(fileName.lastIndexOf(".") + 1); } /** * 生成文件名(避免重名) * @param originalFilename 原始文件名 * @return 新文件名 */ public static String generateFileName(String originalFilename) { String extension = ""; String name = originalFilename; if (originalFilename != null && originalFilename.lastIndexOf(".") != -1) { extension = originalFilename.substring(originalFilename.lastIndexOf(".")); name = originalFilename.substring(0, originalFilename.lastIndexOf(".")); } // 使用时间戳+随机数避免重名 String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); String random = String.valueOf(new Random().nextInt(1000)); return name + timestamp + random + extension; } /** * 生成文件保存路径 * @param baseUploadPath 基础上传路径 * @param 业务文件夹 * @param fileName 文件名 * @param fileExtension 文件扩展名 * @return 完整保存路径 */ public static String generateSavePath(String baseUploadPath, String fileName, String fileExtension) { // 标准化路径分隔符 String separator ="/"; // 构建路径 StringBuilder pathBuilder = new StringBuilder(); pathBuilder.append(normalizePath(baseUploadPath)).append(separator); // 添加业务文件夹 // if (businessFolder != null && !businessFolder.trim().isEmpty()) { // pathBuilder.append(normalizePath(businessFolder)).append(separator); // } // 添加日期文件夹(按年月日分类) String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); pathBuilder.append(datePath).append(separator); // 添加文件名 pathBuilder.append(fileName); return pathBuilder.toString(); } /** * 标准化路径(处理跨平台路径分隔符) * @param path 路径 * @return 标准化后的路径 */ private static String normalizePath(String path) { if (path == null) { return null; } // 将所有反斜杠替换为正斜杠,然后根据系统转换 return path.replace("\\", "/").replace("/", File.separator); } /** * 创建目录(支持跨平台) * @param filePath 文件路径 * @throws IOException IO异常 */ private static void createDirectories(String filePath) throws IOException { Path path = Paths.get(filePath); Path parentDir = path.getParent(); if (parentDir != null && !Files.exists(parentDir)) { Files.createDirectories(parentDir); } } /** * 设置允许的文件扩展名 * @param extensions 扩展名列表 */ public static void setAllowedExtensions(Set extensions) { ALLOWED_EXTENSIONS.clear(); ALLOWED_EXTENSIONS.addAll(extensions); } /** * 设置最大文件大小 * @param maxSize 最大大小(字节) */ public static void setMaxFileSize(long maxSize) { MAX_FILE_SIZE = maxSize; } }