FileUploadUtil.java 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. package com.hotent.util;
  2. import com.hotent.baseInfo.vo.FileUploadResult;
  3. import com.hotent.config.EipConfig;
  4. import com.hotent.constant.BaseConstant;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.apache.commons.lang.StringUtils;
  7. import org.springframework.web.multipart.MultipartFile;
  8. import java.io.File;
  9. import java.io.IOException;
  10. import java.nio.file.Files;
  11. import java.nio.file.Path;
  12. import java.nio.file.Paths;
  13. import java.time.LocalDateTime;
  14. import java.time.format.DateTimeFormatter;
  15. import java.util.*;
  16. @Slf4j
  17. public class FileUploadUtil {
  18. // 允许上传的文件类型
  19. private static final Set<String> ALLOWED_EXTENSIONS = new HashSet<>(Arrays.asList(
  20. // 文档格式
  21. "doc", "docx", "xls", "xlsx", "ppt", "pptx", "pdf", "txt",
  22. // 图片格式
  23. "jpg", "jpeg", "png", "gif", "bmp", "webp",
  24. // 压缩包格式
  25. "zip", "rar", "7z",
  26. // 其他常用格式
  27. "csv", "xml", "json"
  28. ));
  29. // 文件大小限制 (单位: 字节,默认100MB)
  30. private static long MAX_FILE_SIZE = 100 * 1024 * 1024;
  31. /**
  32. * 单文件上传
  33. * @param file 上传的文件
  34. * @param businessFolder 业务文件夹名称
  35. * @param baseUploadPath 基础上传路径
  36. * @return 文件上传结果
  37. */
  38. public static FileUploadResult uploadFile(MultipartFile file, String baseUploadPath) {
  39. return uploadFiles(Collections.singletonList(file), baseUploadPath).get(0);
  40. }
  41. /**
  42. * 多文件上传
  43. * @param files 上传的文件列表
  44. * @param 业务文件夹名称
  45. * @param baseUploadPath 基础上传路径
  46. * @return 文件上传结果列表
  47. */
  48. public static List<FileUploadResult> uploadFiles(List<MultipartFile> files, String baseUploadPath) {
  49. List<FileUploadResult> results = new ArrayList<>();
  50. for (MultipartFile file : files) {
  51. FileUploadResult result = new FileUploadResult();
  52. result.setOriginalFilename(file.getOriginalFilename());
  53. try {
  54. // 验证文件
  55. validateFile(file);
  56. // 生成文件保存路径
  57. String fileExtension = getFileExtension(file.getOriginalFilename());
  58. String fileName = generateFileName(file.getOriginalFilename());
  59. String savePath = generateSavePath(baseUploadPath, fileName, fileExtension);
  60. // 创建目录
  61. createDirectories(savePath);
  62. log.info(savePath);
  63. // 保存文件
  64. File destFile = new File(savePath);
  65. file.transferTo(destFile);
  66. // 设置成功结果
  67. result.setFileName(fileName);
  68. result.setFileExtension(fileExtension);
  69. result.setSavePath(getPathFileName(savePath,fileName));
  70. result.setFileSize(file.getSize());
  71. result.setMessage("上传成功");
  72. } catch (Exception e) {
  73. result.setMessage("上传失败: " + e.getMessage());
  74. }
  75. results.add(result);
  76. }
  77. return results;
  78. }
  79. public static final String getPathFileName(String uploadDir, String fileName)
  80. {
  81. int dirLastIndex = EipConfig.getProfile().length() + 1;
  82. String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
  83. return BaseConstant.RESOURCE_PREFIX + "/" + currentDir;
  84. }
  85. /**
  86. * 验证文件合法性
  87. * @param file 文件
  88. * @throws Exception 验证异常
  89. */
  90. private static void validateFile(MultipartFile file) throws Exception {
  91. // 检查文件是否为空
  92. if (file.isEmpty()) {
  93. throw new Exception("文件为空");
  94. }
  95. // 检查文件大小
  96. if (file.getSize() > MAX_FILE_SIZE) {
  97. throw new Exception("文件大小超过限制(" + MAX_FILE_SIZE / (1024 * 1024) + "MB)");
  98. }
  99. // 检查文件类型
  100. String extension = getFileExtension(file.getOriginalFilename());
  101. if (!ALLOWED_EXTENSIONS.contains(extension.toLowerCase())) {
  102. throw new Exception("不支持的文件类型: " + extension);
  103. }
  104. }
  105. public static String getFileType(String fileName)
  106. {
  107. int separatorIndex = fileName.lastIndexOf(".");
  108. if (separatorIndex < 0)
  109. {
  110. return "";
  111. }
  112. return fileName.substring(separatorIndex + 1).toLowerCase();
  113. }
  114. public static boolean checkAllowDownload(String resource)
  115. {
  116. // 禁止目录上跳级别
  117. if (StringUtils.contains(resource, ".."))
  118. {
  119. return false;
  120. }
  121. if (ALLOWED_EXTENSIONS.contains(resource)) {
  122. return true;
  123. }
  124. // 不在允许下载的文件规则
  125. return false;
  126. }
  127. /**
  128. * 获取文件扩展名
  129. * @param fileName 文件名
  130. * @return 文件扩展名
  131. */
  132. public static String getFileExtension(String fileName) {
  133. if (fileName == null || fileName.lastIndexOf(".") == -1) {
  134. return "";
  135. }
  136. return fileName.substring(fileName.lastIndexOf(".") + 1);
  137. }
  138. /**
  139. * 生成文件名(避免重名)
  140. * @param originalFilename 原始文件名
  141. * @return 新文件名
  142. */
  143. public static String generateFileName(String originalFilename) {
  144. String extension = "";
  145. String name = originalFilename;
  146. if (originalFilename != null && originalFilename.lastIndexOf(".") != -1) {
  147. extension = originalFilename.substring(originalFilename.lastIndexOf("."));
  148. name = originalFilename.substring(0, originalFilename.lastIndexOf("."));
  149. }
  150. // 使用时间戳+随机数避免重名
  151. String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
  152. String random = String.valueOf(new Random().nextInt(1000));
  153. return name + timestamp + random + extension;
  154. }
  155. /**
  156. * 生成文件保存路径
  157. * @param baseUploadPath 基础上传路径
  158. * @param 业务文件夹
  159. * @param fileName 文件名
  160. * @param fileExtension 文件扩展名
  161. * @return 完整保存路径
  162. */
  163. public static String generateSavePath(String baseUploadPath, String fileName, String fileExtension) {
  164. // 标准化路径分隔符
  165. String separator ="/";
  166. // 构建路径
  167. StringBuilder pathBuilder = new StringBuilder();
  168. pathBuilder.append(normalizePath(baseUploadPath)).append(separator);
  169. // 添加业务文件夹
  170. // if (businessFolder != null && !businessFolder.trim().isEmpty()) {
  171. // pathBuilder.append(normalizePath(businessFolder)).append(separator);
  172. // }
  173. // 添加日期文件夹(按年月日分类)
  174. String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
  175. pathBuilder.append(datePath).append(separator);
  176. // 添加文件名
  177. pathBuilder.append(fileName);
  178. return pathBuilder.toString();
  179. }
  180. /**
  181. * 标准化路径(处理跨平台路径分隔符)
  182. * @param path 路径
  183. * @return 标准化后的路径
  184. */
  185. private static String normalizePath(String path) {
  186. if (path == null) {
  187. return null;
  188. }
  189. // 将所有反斜杠替换为正斜杠,然后根据系统转换
  190. return path.replace("\\", "/").replace("/", File.separator);
  191. }
  192. /**
  193. * 创建目录(支持跨平台)
  194. * @param filePath 文件路径
  195. * @throws IOException IO异常
  196. */
  197. private static void createDirectories(String filePath) throws IOException {
  198. Path path = Paths.get(filePath);
  199. Path parentDir = path.getParent();
  200. if (parentDir != null && !Files.exists(parentDir)) {
  201. Files.createDirectories(parentDir);
  202. }
  203. }
  204. /**
  205. * 设置允许的文件扩展名
  206. * @param extensions 扩展名列表
  207. */
  208. public static void setAllowedExtensions(Set<String> extensions) {
  209. ALLOWED_EXTENSIONS.clear();
  210. ALLOWED_EXTENSIONS.addAll(extensions);
  211. }
  212. /**
  213. * 设置最大文件大小
  214. * @param maxSize 最大大小(字节)
  215. */
  216. public static void setMaxFileSize(long maxSize) {
  217. MAX_FILE_SIZE = maxSize;
  218. }
  219. }