UploadController.java 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package modules.upload;
  2. import com.jfinal.aop.Before;
  3. import com.jfinal.kit.StrKit;
  4. import com.jfinal.upload.UploadFile;
  5. import common.interceptor.LoginInterceptor;
  6. import common.interceptor.role.RequiredRoleInterface;
  7. import common.utils.http.MyController;
  8. import common.utils.http.MyRet;
  9. import modules.user.UserController;
  10. import java.io.File;
  11. import java.io.IOException;
  12. import java.nio.file.Files;
  13. import java.nio.file.StandardCopyOption;
  14. import java.text.SimpleDateFormat;
  15. import java.util.Date;
  16. import java.util.UUID;
  17. public class UploadController extends MyController {
  18. // 默认上传文件保存的基路径,可以从配置文件中读取
  19. private static final String DEFAULT_UPLOAD_BASE_PATH = System.getenv("UPLOAD_BASE_PATH");
  20. // 默认的URL访问基路径,可以从配置文件中读取
  21. private static final String DEFAULT_URL_BASE = System.getenv("URL_BASE") + "/uploads";
  22. /**
  23. * 上传一个文件的方法
  24. * 前端通过 multipart/form-data 方式,将文件字段命名为 "file" 上传
  25. */
  26. @Before(LoginInterceptor.class)
  27. @RequiredRoleInterface({UserController.ROLE_SUPER_ADMIN})
  28. public void uploadOneFile() {
  29. UploadFile uploadFile = getFile("file");
  30. if (uploadFile == null) {
  31. renderJson(MyRet.fail("请上传文件"));
  32. return;
  33. }
  34. File tempFile = uploadFile.getFile(); // 获取 JFinal 上传的临时文件
  35. // important: uploadFile instance is useful so we don't delete it directly.
  36. try {
  37. String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
  38. String extension = getFileExtension(uploadFile.getOriginalFileName());
  39. String uniqueFileName = UUID.randomUUID().toString().replace("-", "") + extension;
  40. File destDir = new File(DEFAULT_UPLOAD_BASE_PATH, today);
  41. if (!destDir.exists()) {
  42. if (!destDir.mkdirs()) {
  43. throw new RuntimeException("创建目标目录失败: " + destDir.getAbsolutePath());
  44. }
  45. }
  46. File destFile = new File(destDir, uniqueFileName);
  47. // --- 核心修改部分 ---
  48. // 使用 Files.move() 进行移动操作
  49. // StandardCopyOption.REPLACE_EXISTING: 如果目标文件已存在,则替换掉它
  50. // StandardCopyOption.ATOMIC_MOVE: 尝试进行原子性移动,如果不支持原子性则回退到非原子性
  51. Files.move(tempFile.toPath(), destFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
  52. // --- 核心修改部分结束 ---
  53. String accessUrl = DEFAULT_URL_BASE + "/" + today + "/" + uniqueFileName;
  54. renderJson(MyRet.ok("上传成功").setData(accessUrl));
  55. } catch (IOException e) { // 捕获 IOException,Files.move 可能会抛出
  56. // 移动失败,打印详细错误信息
  57. e.printStackTrace();
  58. renderJson(MyRet.fail("文件移动失败,请检查服务器日志: " + e.getMessage()));
  59. } catch (Exception e) { // 其他异常
  60. e.printStackTrace();
  61. renderJson(MyRet.fail("上传失败: " + e.getMessage()));
  62. } finally {
  63. // 无论成功失败,确保临时文件被删除
  64. // 如果 Files.move 成功,tempFile 会被删除
  65. // 如果 Files.move 失败,tempFile 仍然存在,需要手动删除
  66. if (tempFile != null && tempFile.exists()) {
  67. tempFile.delete();
  68. }
  69. }
  70. }
  71. /**
  72. * 获取文件扩展名
  73. * @param fileName 文件名
  74. * @return 扩展名,包含".",例如 ".jpg"
  75. */
  76. private String getFileExtension(String fileName) {
  77. if (StrKit.isBlank(fileName) || fileName.lastIndexOf('.') == -1) {
  78. return "";
  79. }
  80. return fileName.substring(fileName.lastIndexOf('.'));
  81. }
  82. }