Spring MVC 檔案上傳核心在於 MultipartResolver 處理 multipart/form-data 請求,配合 @RequestParam MultipartFile 或 MultipartHttpServletRequest 取得檔案。本文涵蓋 XML/Java Config 兩種配置、單/多檔案 Controller 寫法、大小限制與異常處理。
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760" /> <!-- 10MB 總大小 -->
<property name="maxUploadSizePerFile" value="5242880" /> <!-- 5MB 單檔 -->
<property name="defaultEncoding" value="UTF-8" />
</bean>
<!-- 超過大小限制的異常導向頁面 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">
error/fileSizeExceeded
</prop>
</props>
</property>
</bean>
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver r = new CommonsMultipartResolver();
r.setMaxUploadSize(10_485_760L); // 10MB
r.setMaxUploadSizePerFile(5_242_880L); // 5MB
r.setDefaultEncoding(StandardCharsets.UTF_8.name());
return r;
}
}
<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>
<form method="POST" action="/upload" enctype="multipart/form-data">
<input type="file" name="files" multiple /> <!-- multiple 允許多選 -->
<button type="submit">上傳</button>
</form>
@PostMapping("/upload")
public String uploadFiles(@RequestParam("files") MultipartFile[] files,
RedirectAttributes redirectAttrs) {
if (files == null || files.length == 0) {
redirectAttrs.addFlashAttribute("msg", "請選擇檔案");
return "redirect:/uploadForm";
}
for (MultipartFile file : files) {
if (file.isEmpty()) continue;
try {
String original = file.getOriginalFilename();
Path dest = Paths.get("/data/uploads", original);
Files.copy(file.getInputStream(), dest, StandardCopyOption.REPLACE_EXISTING);
redirectAttrs.addFlashAttribute("msg", "上傳成功: " + original);
} catch (IOException e) {
redirectAttrs.addFlashAttribute("msg", "上傳失敗: " + e.getMessage());
}
}
return "redirect:/uploadForm";
}
@PostMapping("/upload2")
public String uploadViaRequest(HttpServletRequest request) {
MultipartHttpServletRequest mpReq = (MultipartHttpServletRequest) request;
// 單檔
MultipartFile file = mpReq.getFile("file");
// 多檔
List<MultipartFile> files = mpReq.getFiles("files");
// 其餘邏輯同寫法 A
return "result";
}
public class UploadForm {
private MultipartFile[] files;
private String description;
// getter/setter
}
@PostMapping("/upload3")
public String uploadWithForm(@Valid UploadForm form, BindingResult binding) {
if (binding.hasErrors()) return "uploadForm";
// 使用 form.getFiles()
return "success";
}
| 問題 | 原因 | 解決 |
|---|---|---|
| Controller 進不去、400 Bad Request | 缺少 enctype="multipart/form-data" | 檢查 form 標籤 |
MultipartFile 為 null | 參數名與 name 不符 | 確保 @RequestParam("files") 對應 name="files" |
| 大檔案上傳失敗 | 超過 maxUploadSize 或 Tomcat maxPostSize | 調大兩邊設定,或啟用流式上傳 |
| 中文檔名亂碼 | 瀏覽器編碼不一 | Spring 5+ 自動處理;舊版可用 StandardCharsets.ISO_8859_1 轉 UTF-8 |