在 Java Web 開發中,FileItem 是 Apache Commons FileUpload 庫的核心類,封裝了表單欄位與上傳文件的數據。掌握其常用方法對於實現健壯的文件上傳功能至關重要。本文將系統梳理 10 個核心方法的用法與注意事項。
| 方法 | 返回類型 | 用途 | 關鍵注意點 |
|---|---|---|---|
isFormField() | boolean | 判斷是普通表單欄位還是文件欄位 | true=普通欄位,false=文件上傳 |
getName() | String | 獲取上傳文件的文件名 | IE 返回完整路徑,Firefox/Chrome 僅返回文件名 |
getFieldName() | String | 獲取表單標籤的 name 屬性值 | 對應 <input name="..."> |
write(File) | void | 將文件內容寫入指定路徑 | 執行後臨時文件可能被刪除 |
getString() | String | 獲取欄位字符串內容 | 支援編碼參數,解決中文亂碼 |
getContentType() | String | 獲取文件 MIME 類型 | 普通欄位返回 null |
isInMemory() | boolean | 判斷數據是否在內存中 | true=內存,false=臨時文件 |
delete() | void | 刪除臨時文件/清理資源 | 建議及時調用釋放磁盤空間 |
getInputStream() | InputStream | 以流形式讀取文件數據 | 適合大文件流式處理 |
getSize() | long | 獲取文件大小(位元組) | 上傳前驗證文件大小限制 |
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
if (item.isFormField()) {
// 處理普通表單欄位:username、password 等
String fieldName = item.getFieldName();
String value = item.getString("UTF-8");
} else {
// 處理文件上傳
String fileName = item.getName();
// ...
}
}
瀏覽器差異:
C:\Users\Admin\Documents\photo.jpgphoto.jpg統一處理最佳實踐:
String fileName = item.getName();
if (fileName != null) {
fileName = fileName.substring(fileName.lastIndexOf(File.separator) + 1);
// 進一步處理:UUID 重命名、副檔名驗證等
}
// 錯誤示範:使用預設編碼導致中文亂碼
String value = item.getString();
// 正確做法:顯式指定 UTF-8
String value = item.getString("UTF-8");
| 場景 | 推薦方法 | 原因 |
|---|---|---|
| 小文件、直接落盤 | write() | API 簡單,自動處理臨時文件清理 |
| 大文件、雲存儲、流式處理 | getInputStream() | 避免內存溢出,支援分塊上傳 |
| 需讀取內容再決定存儲 | getInputStream() | 可先驗證內容(如圖片格式、病毒掃描) |
try {
// 文件處理邏輯
item.write(targetFile);
} finally {
// 確保臨時文件被清理,防止磁盤佔用
item.delete();
}
注意: 雖然 GC 會最終清理,但高併發下臨時文件堆積會導致磁盤空間耗盡,finally 區塊調用 delete() 是最佳實踐。
@PostMapping("/upload")
public ResponseEntity<String> handleUpload(HttpServletRequest request) {
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
upload.setHeaderEncoding("UTF-8");
try {
List<FileItem> items = upload.parseRequest(request);
for (FileItem item : items) {
if (item.isFormField()) {
// 普通欄位處理
formData.put(item.getFieldName(), item.getString("UTF-8"));
} else {
// 文件處理
String originalName = item.getName();
if (originalName == null || originalName.isEmpty()) continue;
String safeName = originalName.substring(
originalName.lastIndexOf(File.separator) + 1
);
String contentType = item.getContentType();
long size = item.getSize();
// 業務驗證:類型、大小限制
if (!allowedTypes.contains(contentType)) {
return ResponseEntity.badRequest().body("不支援的文件類型");
}
if (size > MAX_SIZE) {
return ResponseEntity.badRequest().body("文件過大");
}
// 存儲:使用 UUID 避免衝突
String ext = safeName.substring(safeName.lastIndexOf('.'));
String storedName = UUID.randomUUID() + ext;
File dest = new File(UPLOAD_DIR, storedName);
item.write(dest); // 或使用 getInputStream() 配合 Files.copy()
// 記錄元數據到數據庫
fileService.saveMetadata(safeName, storedName, contentType, size);
}
}
return ResponseEntity.ok("上傳成功");
} catch (Exception e) {
log.error("上傳失敗", e);
return ResponseEntity.internalServerError().body("上傳異常");
}
}
getString("UTF-8"),並確保 ServletFileUpload.setHeaderEncoding("UTF-8")finally 中調用 delete()DiskFileItemFactory.setSizeThreshold()FileItem 雖然 API 簡單,但細節決定成敗。掌握其 10 個核心方法的語義與邊界條件,配合恰當的異常處理與安全防護,即可構建企業級的文件上傳服務。建議收藏本文作為開發參考手冊。