一、依賴準備
<!-- pom.xml -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
二、Spring 配置 MultipartResolver
<!-- spring-mvc.xml -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="104857600" /> <!-- 100MB -->
<property name="maxInMemorySize" value="4096" /> <!-- 4KB 閾值,超過寫入臨時檔 -->
<property name="defaultEncoding" value="UTF-8" />
<property name="resolveLazily" value="true" /> <!-- 延遲解析,支援非 multipart 請求 -->
</bean>
三、前端表單關鍵點
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="text" name="startDate" placeholder="開始日期" />
<input type="text" name="endDate" placeholder="結束日期" />
<input type="file" name="uploadFile" /> <!-- name 需與 Controller 參數一致 -->
<button type="submit">上傳</button>
</form>
四、Controller 處理上傳
@PostMapping("/upload")
public String upload(
@RequestParam("startDate") String startDate,
@RequestParam("endDate") String endDate,
@RequestParam("uploadFile") MultipartFile file,
HttpServletRequest request,
RedirectAttributes redirectAttributes) {
log.info("startDate={}, endDate={}, fileName={}, size={}",
startDate, endDate, file.getOriginalFilename(), file.getSize());
if (file.isEmpty()) {
redirectAttributes.addFlashAttribute("error", "請選擇檔案");
return "redirect:/uploadPage";
}
try (InputStream is = file.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
String line;
while ((line = br.readLine()) != null) {
// 處理每行業務邏輯
log.debug("處理行: {}", line);
}
redirectAttributes.addFlashAttribute("success", "上傳成功,共處理 " + count + " 筆資料");
} catch (IOException e) {
log.error("檔案讀取失敗", e);
redirectAttributes.addFlashAttribute("error", "檔案讀取失敗: " + e.getMessage());
}
return "redirect:/uploadPage";
}
五、關鍵細節與優化
1. MultipartFile 核心方法
| 方法 | 說明 |
getOriginalFilename() | 客戶端原始檔名(可能含路徑,需清理) |
getInputStream() | 檔案輸入流(記得關閉) |
getBytes() | 完整讀入 byte[](大檔案慎用,OOM 風險) |
transferTo(File dest) | 直接存檔(高效,底層用 FileChannel) |
getSize() | 檔案大小(bytes) |
getContentType() | MIME 類型 |
2. 大檔案優化策略
- 分片上傳:前端切片(如 5MB/片),後端合併,支援斷點續傳
- 流式處理:避免
getBytes() 全量載入,用 getInputStream() 邊讀邊處理
- 異步處理:上傳後立即返回,後台任務佇列處理(@Async / MQ)
- 臨時目錄:配置
spring.servlet.multipart.location 指定 SSD 目錄
3. Spring Boot 2.x+ 簡化配置
# application.yml
spring:
servlet:
multipart:
enabled: true
max-file-size: 100MB
max-request-size: 100MB
file-size-threshold: 4KB
location: /data/tmp/upload # 臨時檔目錄
4. 常見錯誤排查
| 錯誤 | 原因 | 解決 |
| MultipartFile 為 null | 表單缺少 enctype、參數名不匹配 | 檢查 enctype="multipart/form-data"、@RequestParam name 一致 |
| Maximum upload size exceeded | 超過配置限制 | 調大 maxUploadSize / max-file-size |
| Missing ServletRequestPart | 非 multipart 請求 | 確認 Content-Type、resolveLazily=true |
| 中文檔名亂碼 | 編碼不一致 | defaultEncoding=UTF-8、Tomcat URIEncoding=UTF-8 |