Spring MVC 文件上傳
1. 前言
實現(xiàn)文件上傳有很多方案。如使用原始的 IO 流或者使用第三方上傳插件。
Spring MVC 自帶有文件上傳組件,能很容易地實現(xiàn)文件上傳功能。
本節(jié)課程將和大家一起講解 Spring MVC 是如何處理文件上傳的。通過本章節(jié)內(nèi)容的學習,你將掌握使用 MultipartResolver 相關組件簡單的實現(xiàn)文件上傳。
2. MultipartResolver 組件
多數(shù)情況下,頁面中的數(shù)據(jù)都是以字符串格式發(fā)送給服務器。但有時,用戶需要上傳自己的個人頭像或者上傳文件,或者說以二進制的方式進行數(shù)據(jù)傳送。這時就不能使用字符串的方式傳遞數(shù)據(jù)了。
Spring MVC 提供有 MultipartResolver 相關組件實現(xiàn)文件上傳,不需要特別引入第三方模塊。默認情況下,Spring MVC 沒有啟用文件上傳組件,使用前需要做些簡單的配置。
2.1 配置文件上傳組件
打開項目中的 WebConfig 文件,添加如下代碼:
@Bean
public MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
MultipartResolver 是一個接口,約定了文件上傳的方法。StandardServletMultipartResolver 是具體的實現(xiàn)類,用來完成文件上傳。
對上傳的文件信息進一步進行配置,如限制文件大小、文件類型等。打開 WebInitializer 文件,重寫 customizeRegistration() 方法:
@Override
protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig(new MultipartConfigElement(null,2000000,400000,0));
}
MultipartConfigElement()方法可以接收 3 個參數(shù):
- 第一個參數(shù)指定保存上傳文件的臨時目錄。如果指定 null,由 Spring MVC 自己提供;最好不要指定;
- 第二個參數(shù),文件上傳的最小大小限制;
- 第三個參數(shù),文件上傳的最大尺寸限制。
2.2 實現(xiàn)流程
準備工作完成,現(xiàn)在實現(xiàn)文件上傳。
- 編寫提交表單;
<form action="upload" method="POST" enctype="multipart/form-data">
選擇文件:<input type="file" name="file" value="" /> <br />
<input type="submit" name="upload" value="上傳" />
</form>
表單的 enctype 屬性有如下幾個選擇:
- application/x-www-form-urlencoded : 在發(fā)送前編碼所有字符,數(shù)據(jù)以字符串的方式發(fā)送;
- multipart/form-data: 不對字符編碼,使用包含文件上傳控件的表單時,必須使用該值;
- text/plain: 空格轉(zhuǎn)換為 “+” 加號,但不對特殊字符編碼。
Tips: 因為表單中包含有文件上傳控件,所以,一定要設置表單的 enctype 值為 multipart/form-data。
- 獲取項目上下文絕對路徑;
編寫控制器之前,先打開 web.xml ,注冊一個 org.springframework.web.util.WebAppRootListener 監(jiān)聽器,通過此監(jiān)聽器獲取到 Spring MVC 項目的發(fā)布的絕對路徑,用來為上傳的文件指定存儲位置。
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>webapp.root</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
</listener>
Tips: webapp.root 相當于一個變量,可以是符合規(guī)范的任意命稱。當程序啟動時,此監(jiān)聽器會把服務器絕對路徑保存在此變量中。使用監(jiān)聽器的方式獲取路徑可以有效地減少開發(fā)者的編碼量。
當然,完全可以不使用此監(jiān)聽器,開發(fā)者可以在控制器中通過注入原生 Servlet API 編碼獲取。
- 編寫控制器:
@Controller
public class UpLoadAction {
@RequestMapping("/upload")
public String upload(@RequestPart("upFile") byte[] file) throws IOException {
String path = System.getProperty("webapp.root");
String filePath = path + "\\upload\\temp.png";
FileOutputStream fileOutputStream = new FileOutputStream(filePath);
FileCopyUtils.copy(file, fileOutputStream);
return "success";
}
}
解釋上面的代碼:
- System.getProperty(“webapp.root”) 可以得到監(jiān)聽器組件得到的項目上下文路徑。在項目的根目錄下新建 upload 目錄,用來存儲上傳過來的文件;
- @RequestPart(“upFile”) 注解能注入表單提交上來的文件數(shù)據(jù),此數(shù)據(jù)以 byte[] 類型保存。
使用 @RequestPart(“upFile”) 注解的方式存在些問題,不能獲取上傳文件的文件名等其它元數(shù)據(jù)信息。
- 實例測試。
打開瀏覽器,顯示上傳頁面。
在本地首先選擇好需要上傳的文件,然后點擊上傳。找到 tomcat 中的項目發(fā)布目錄,可以找到剛上傳的文件。
2.3 MultipartFile 接口
以字節(jié)數(shù)組的方式接收上傳的文件數(shù)據(jù),過于原始、低級,很難獲取到文件的元數(shù)據(jù)。Spring MVC 提供有 MultipartFile 接口。
查看 MultipartFile 接口源代碼,可以知道 MultipartFile 接口提供了很多方法,能解析出上傳文件的更多元數(shù)據(jù),包括文件名、文件大小等,方便開發(fā)者更靈活地處理數(shù)據(jù)。
public interface MultipartFile extends InputStreamSource {
String getName();
@Nullable
String getOriginalFilename();
@Nullable
String getContentType();
boolean isEmpty();
long getSize();
byte[] getBytes() throws IOException;
@Override
InputStream getInputStream() throws IOException;
default Resource getResource() {
return new MultipartFileResource(this);
}
void transferTo(File dest) throws IOException, IllegalStateException;
default void transferTo(Path dest) throws IOException, IllegalStateException {
FileCopyUtils.copy(getInputStream(), Files.newOutputStream(dest));
}
}
MultipartFile 最常用的是 transferTo 方法,用來把上傳文件存儲到指定位置。
重構(gòu)上面的控制器代碼。
@RequestMapping("/upload")
public String upload(@RequestPart("upFile") MultipartFile file) throws IOException {
String path = System.getProperty("webapp.root");
String filePath = path + "\\upload\\"+file.getOriginalFilename();
System.out.println(filePath);
file.transferTo(new File(filePath));
return "success";
}
如上面一樣測試文件上傳,結(jié)果沒有什么不一樣。
3. 小結(jié)
本節(jié)和大家講解了如何使用 Spring MVC 提供的 MultipartResolver 組件完成文件的上傳。其配置過程并不很難,但大家需要注意的是,在接收文件數(shù)據(jù)時會涉及到 @RequestPart 注解、MultipartFile 接口,結(jié)合兩者能很好的注放上傳數(shù)據(jù),方便開發(fā)者的后續(xù)處理。