Spring MVC 提供統一的 MultipartFile 抽象,底層可插拔 CommonsMultipartResolver (Apache Commons FileUpload) 或 StandardServletMultipartResolver (Servlet 3.0+ 內置)。本文對比兩種方案,並演示 HTML5 多文件上傳與進度條實現。
<form:form action="product_save" method="post" commandName="product" enctype="multipart/form-data">
<form:input path="name"/>
<form:input path="description"/>
<form:input path="price"/>
<input type="file" name="images[0]"/> <!-- HTML5 多文件可用 name="images" multiple -->
<input type="submit"/>
</form:form>
public class Product implements Serializable {
private Long id;
private String name, description, price;
private List<MultipartFile> images; // 接收上傳文件列表
// Getter/Setter
}
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="2000000"/> <!-- 2MB -->
</bean>
<mvc:resources mapping="/image/**" location="/image/"/> <!-- 靜態資源映射 -->
@PostMapping("/product_save")
public String save(HttpServletRequest req, @ModelAttribute Product product, BindingResult br, Model model) {
List<MultipartFile> files = product.getImages();
if (files != null) {
for (MultipartFile f : files) {
if (!f.isEmpty()) {
String fileName = f.getOriginalFilename();
File dest = new File(req.getServletContext().getRealPath("/image"), fileName);
f.transferTo(dest);
}
}
}
model.addAttribute("product", product);
return "ProductDetails";
}
multipart-config<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<multipart-config>
<max-file-size>20848820</max-file-size> <!-- 20MB -->
<max-request-size>418018841</max-request-size> <!-- 400MB -->
<file-size-threshold>1048576</file-size-threshold> <!-- 1MB 超過寫磁盤 -->
<location>/image/</location> <!-- 臨時文件目錄 -->
</multipart-config>
</servlet>
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
public class UploadFile { private MultipartFile multipartFile; /* getter/setter */ }
@PostMapping("/file_upload")
@ResponseBody
public void upload(HttpServletRequest req, @ModelAttribute UploadFile uf, BindingResult br) {
MultipartFile f = uf.getMultipartFile();
File dest = new File(req.getServletContext().getRealPath("/image"), f.getOriginalFilename());
f.transferTo(dest);
}
<input type="file" id="files" multiple>
<button id="upLoadButton">Upload</button>
<div id="bar">0%</div>
<script>
var totalSize = 0, uploaded = 0, fileCount = 0, uploadedCount = 0;
$('#files').on('change', function(e) {
var files = e.target.files;
fileCount = files.length;
for (var i=0; i= fileCount) return;
var file = $('#files')[0].files[uploadedCount];
var fd = new FormData();
fd.append('multipartFile', file);
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
var pct = Math.round((e.loaded + uploaded) * 100 / totalSize);
$('#bar').css('width', pct + '%').text(pct + '%');
}
};
xhr.onload = function() {
uploaded += file.size;
uploadedCount++;
uploadNext();
};
xhr.open('POST', 'file_upload');
xhr.send(fd);
}
</script>
| 維度 | Commons FileUpload | Servlet 3.0+ 內置 |
|---|---|---|
| 額外依賴 | commons-fileupload、commons-io | 無 |
| 容器要求 | Servlet 2.4+ | Servlet 3.0+ (Tomcat 7+, Jetty 9+) |
| 配置位置 | Spring XML Bean | web.xml + Spring Bean |
| 臨時文件控制 | Resolver 屬性 | web.xml multipart-config |
| 性能 | 成熟穩定 | 原生實現,略優 |
maxUploadSize/max-file-size 防止惡意大文件撐爆磁盤f.getContentType() + 文件頭魔數檢查掌握兩種解析器切換與 HTML5 進度上傳,可應對從傳統表單到現代富交互的各類文件上傳場景。