Spring MVC 內建對文件上傳的優雅支持,核心在於 CommonsMultipartResolver 與 @RequestParam MultipartFile。本文提供從 web.xml、Spring 配置、Controller、前端表單到結果頁的完整可運行示例,並講解關鍵坑點。
<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>
<web-app xmlns="https://java.sun.com/xml/ns/javaee" version="2.5">
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param>
<init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param>
</filter>
<filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/config/applicationContext.xml</param-value>
</context-param>
<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/config/codeifAction.xml</param-value></init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>*.do</url-pattern></servlet-mapping>
</web-app>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.codeif"/>
<!-- 視圖解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>
<!-- 關鍵:文件上傳解析器,id 必須為 multipartResolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="52428800"/> <!-- 50MB -->
<property name="maxInMemorySize" value="1048576"/> <!-- 1MB 閾值 -->
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<!-- 註解映射與適配器 -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
</beans>
<beans ...> <context:component-scan base-package="com.codeif.action"/> </beans>
package com.codeif.action;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import org.springframework.ui.ModelMap;
import java.io.File;
@Controller
public class UploadAction {
@RequestMapping("/upload.do")
public String upload(@RequestParam(value="file", required=false) MultipartFile file,
HttpServletRequest request, ModelMap model) {
if (file == null || file.isEmpty()) {
model.addAttribute("msg", "請選擇文件");
return "result";
}
String uploadDir = request.getSession().getServletContext().getRealPath("/upload");
File dir = new File(uploadDir);
if (!dir.exists()) dir.mkdirs();
String originalName = file.getOriginalFilename();
File target = new File(dir, originalName);
try {
file.transferTo(target); // Spring 封裝的流式寫入,自動處理臨時文件
model.addAttribute("fileUrl", request.getContextPath() + "/upload/" + originalName);
model.addAttribute("msg", "上傳成功");
} catch (Exception e) {
e.printStackTrace();
model.addAttribute("msg", "上傳失敗: " + e.getMessage());
}
return "result";
}
}
<%@ page pageEncoding="UTF-8"%> <html><body> <form action="upload.do" method="post" enctype="multipart/form-data"> <input type="file" name="file" /> <!-- name 需與 @RequestParam value 一致 --> <input type="submit" value="上傳" /> </form> </body></html>
<%@ page pageEncoding="UTF-8"%>
<html><body>
<h3>${msg}</h3>
<c:if test="${not empty fileUrl}">
<img src="${fileUrl}" alt="上傳圖片" style="max-width:300px;"/>
</c:if>
</body></html>
enctype="multipart/form-data",否則 MultipartFile 為 null。multipartResolver,Spring 按名查找,改名即失效。NoClassDefFoundError。<input name="file"> 完全一致,區分大小寫。file.transferTo(targetFile),框架自動處理內存/臨時文件切換、關閉流。@RequestMapping("/multiUpload.do")
public String multi(@RequestParam("files") MultipartFile[] files, ...) {
for (MultipartFile f : files) {
if (!f.isEmpty()) f.transferTo(new File(dir, f.getOriginalFilename()));
}
return "result";
}
前端:<input type="file" name="files" multiple/>
# application.yml
spring:
servlet:
multipart:
max-file-size: 50MB
max-request-size: 100MB
file-size-threshold: 1MB
# Controller 直接用 @RequestParam MultipartFile,無需額外 Bean
Spring MVC 註解式上傳,配置清晰、代碼極簡,掌握核心 Bean 與參數綁定規則,即可輕松應對各類上傳場景。