原文標題為「struts構建文件上傳(六)」,內容即上文補充的 MaintainAction。本文深度剖析其文件寫入、DAO 調用與轉發邏輯,並指出生產級隱患。
MaintainAction.execute()
│
├─► 1. 獲取 FormFile (theFile1)
│
├─► 2. 讀取輸入流 → 寫入服務器磁盤 (FileOutputStream)
│ └─ 關鍵:buffer 8KB、循環寫入、關閉流、destroy() 臨時文件
│
├─► 3. 設置 trainPlan.p_accessory = 文件名
│
├─► 4. trainPlanDAO.addTrainPlan(trainPlan) 入庫
│
└─► 5. request.setAttribute("trainPlain", trainPlan) → forward("trainplanCreated")
| 隱患 | 風險 | 修正方案 |
|---|---|---|
request.getRealPath("/") 獲取路徑 | WAR 解壓路徑不穩定,重新部署文件丟失;Windows/Linux 路徑分隔符差異 | 配置外部化上傳目錄(servletContext.initParameter、NFS、S3/OSS) |
文件名直接用原名 theFile.getFileName() | 重名覆蓋、特殊字符注入、路徑遍歷攻擊 (../../etc/passwd) | 生成 UUID 文件名 + 原始名存資料庫;FilenameUtils.getName() 防遍歷 |
| 無文件類型/大小驗證 | 惡意上傳腳本、大文件撐爆磁盤 | 白名單驗證 Content-Type/擴展名;struts.multipart.maxSize + 代碼雙重限制 |
| 單線程同步寫入大文件 | 阻塞 Web 線程,併發下吞吐量劇降 | 異步處理(線程池/消息隊列)、前端直傳對象存儲 |
| DAO 直接 new,無事務管理 | 文件寫入成功但入庫失敗 → 數據不一致;連接洩漏 | Spring @Transactional 統一事務;連接池管理 DataSource |
| 異常捕獲後僅 printStackTrace | 用戶無感知,日誌難追蹤 | 統一異常處理器,記錄結構化日誌,返回友好錯誤頁 |
// 服務層方法(Spring @Service + @Transactional) public Trainplan createTrainPlan(Trainplan plan, Listfiles) { List savedNames = new ArrayList<>(); for (FormFile file : files) { if (file == null || file.getFileSize() == 0) continue; validateFile(file); // 類型、大小 String storedName = storeFile(file); // 寫入配置目錄或 OSS,返回 UUID 名 savedNames.add(storedName); } plan.setAttachments(String.join(",", savedNames)); // 或關聯表批量插入 trainPlanDAO.insert(plan); return plan; } // Action 僅做轉換與跳轉 public ActionForward execute(...) { try { Trainplan plan = maintainForm.getTrainPlan(); List files = Arrays.asList( maintainForm.getTheFile1(), maintainForm.getTheFile2(), maintainForm.getTheFile3() ); Trainplan saved = trainPlanService.createTrainPlan(plan, files); request.setAttribute("trainPlan", saved); // 修正拼寫 trainPlan return mapping.findForward("success"); } catch (BusinessException e) { saveErrors(request, e.getActionMessages()); return mapping.getInputForward(); } }
FormFile → MultipartFile,Action → @Controller,ActionForm → @ModelAttribute / DTO。bucket/key,應用無狀態化支援水平擴展。經典代碼承載了時代記憶,重構思路才是永恆價值。