SpringMVC上傳文件的 4 種方式,你都會么?| SpringMVC第6篇
大家好,我是【路人甲 Java】號主路人,本文如果對你有幫助,點(diǎn)個在看,順便忙轉(zhuǎn)發(fā)一下,非常需要大家的支持,對 java 有興趣的朋友歡迎加我微信 itsoku 交流。
1、本文內(nèi)容
文件上傳開發(fā)步驟 單文件上傳 多文件上傳 通過 MultipartHttpServletRequest 處理文件上傳 通過自定義對象接收上傳的文件 擴(kuò)展知識 案例代碼
2、預(yù)備知識
springmvc 系列中的測試案例,基本上都是使用 idea 中的 http client 插件開發(fā)的,是一款非常高效的接口測試工具,還沒有用過的,建議先去了解下用法:idea 中的接口測試?yán)鳎╤ttp cient 插件)
3、軟件版本
idea 2020.3.3
jdk1.8
≥maven3.6.1
spring5.3.6
apache-tomcat-9.0.46
4、springmvc 文件上傳步驟
4 個步驟
1、添加 maven 配置
2、springmvc 容器中定義 MultipartResolver 這個 bean
3、controller 中使用 MultipartFile 接收上傳的文件
4、調(diào)用 MultipartFile#transferTo 方法保存文件
5、指定請求類型為:
multipart/form-data
步驟 1:添加 maven 配置
<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.6</version>
</dependency>
步驟 2:定義 MultipartResolver 這個 bean
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSizePerFile" value="#{10*1024*1024}"/>
<property name="maxUploadSize" value="#{100*1024*1024}"/>
</bean>
http 上傳的請求類型為 multipart/form-data 類型,springmvc 內(nèi)部需要為這種請求指定解析器,解析器的類型為
org.springframework.web.multipart.MultipartResolverMultipartResolver 有 2 個實(shí)現(xiàn)類,這里我們使用 CommonsMultipartResolver 作為解析器來解析文件上傳的 http 請求
注意 bean 名稱必須為
multipartResolver兩個比較有用的屬性
maxUploadSizePerFile:單個文件大小限制(byte)
maxUploadSize:整個請求大小限制(byte)
步驟 3:控制器使用 MultipartFile 接收上傳的文件
@RequestMapping("/upload1.do")
public ModelAndView upload1(@RequestParam("file1") MultipartFile f1){
}
步驟 4:調(diào)用 MultipartFile#transferTo 方法保存文件
@RequestMapping("/upload1.do")
public ModelAndView upload1(@RequestParam("file1") MultipartFile f1){
//destFile為目標(biāo)文件,即將上傳的文件寫到destFile中
f1.transferTo(destFile);
}
步驟 5:設(shè)置 http 請求類型為 multipart/form-data
上傳文件,需要設(shè)置 form 表單的 enctype 屬性值為 multipart/form-data

下面來介紹 4 種常用的上傳文件的方式。
5、MultipartFile:上傳的文件對象
springmvc 中使MultipartFile這個類來表示上傳的文件,提供了一系列方法來獲取上傳的文件的信息。
| 方法 | 描述 |
|---|---|
| String getName() | 用來獲取中 name 的名稱 |
| String getOriginalFilename() | 獲取文件的原始名稱 |
| String getContentType() | 獲取文件類型 |
| long getSize() | 獲取文件大小(byte) |
| byte[] getBytes() | 獲取文件內(nèi)容 |
| InputStream getInputStream() | 獲取文件流 |
| void transferTo(File dest) | 將上傳的文件寫到 dest 中 |
6、單文件上傳
控制器中使用一個 MultipartFile 來接收上傳的文件,下面看代碼。
表單代碼
<form method="post" action="upload1.do" enctype="multipart/form-data">
文件:<input type="file" name="file1"><br/>
<input type="submit" value="提交">
</form>
表單中文件元素的 name 為 file1
控制器代碼
/**
* 單文件上傳
* 1、MultipartFile用來接收表單中上傳的文件
* 2、每個MultipartFile對應(yīng)表單中的一個元素
* 3、@RequestParam("f1")用來自動接受表單中的哪個元素?value用來指定表單元素的名稱
*
* @param f1
* @return
* @throws IOException
*/
@RequestMapping("/upload1.do")
public ModelAndView upload1(@RequestParam("file1") MultipartFile f1) throws IOException {
//獲取文件名稱
String originalFilename = f1.getOriginalFilename();
String destFilePath = String.format("E:\\idea\\springmvc-series\\chat04-uploadfile\\src\\main\\webapp\\upfile\\%s", originalFilename);
File destFile = new File(destFilePath);
//調(diào)用transferTo將上傳的文件保存到指定的地址
f1.transferTo(destFile);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/WEB-INF/view/result.jsp");
modelAndView.addObject("msg", destFile.getAbsolutePath());
return modelAndView;
}
上傳的文件會被傳入 update1 方法的第一個參數(shù),注意第一個參數(shù)有個@RequestParam("file1")注解,這個注解的 value 就是表單中文件元素名稱。
7、多文件上傳
當(dāng)上傳多個文件的時候,可以使用多個 MultipartFile 參數(shù)來接收上傳的文件。
表單代碼
<form method="post" action="upload2.do" enctype="multipart/form-data">
文件1:<input type="file" name="file1"><br/>
文件2:<input type="file" name="file2"><br/>
<input type="submit" value="提交">
</form>
控制器代碼
/**
* 多文件上傳
* 1、方法中指定多個MultipartFile,每個MultipartFile對應(yīng)一個上傳的文件
* 2、@RequestParam("file1") 用來指定具體接受上傳的表單中哪個元素的名稱
*
* @param f1
* @param f2
* @return
*/
@RequestMapping("/upload2.do")
public ModelAndView upload2(@RequestParam("file1") MultipartFile f1,
@RequestParam("file2") MultipartFile f2) {
System.out.println("f1:" + f1);
System.out.println("f2:" + f2);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/WEB-INF/view/result.jsp");
modelAndView.addObject("msg", null);
return modelAndView;
}
我們上傳 2 個圖片,控制臺輸出
f1:MultipartFile[field="file1", filename=1.jpg, contentType=image/jpeg, size=145615]
f2:MultipartFile[field="file2", filename=2.jpg, contentType=image/jpeg, size=67713]
8、通過 MultipartHttpServletRequest 處理文件上傳
MultipartHttpServletRequest 接口
1、springmvc 接受到上傳文件的的請求之后,會將請求轉(zhuǎn)換為 MultipartHttpServletRequest 類型的對象
2、MultipartHttpServletRequest 中提供了一系列方法來獲取請求中的所有參數(shù)信息
3、其中 getParameterMap()用來獲取非文件類型的參數(shù)列表
4、getMultiFileMap()方法用來獲取上傳的文件列表

下面來個案例,使用 MultipartHttpServletRequest 來處理上傳的文件請求。
表單代碼
下面表單中有 2 個文本,2 個文件元素。
<form method="post" action="upload3.do" enctype="multipart/form-data">
姓名:<input name="name" value="路人"/> <br/>
年齡:<input name="age" value="30"/><br/>
文件1:<input type="file" name="file1"><br/>
文件2:<input type="file" name="file2"><br/>
<input type="submit" value="提交">
</form>
控制器代碼
控制器中使用 MultipartHttpServletRequest 來獲取所有參數(shù)信息,分了 2 部分獲取
1、先使用 request.getParameterMap()獲取非文件類型的參數(shù),即可以獲取表單中的 name 和 age 這 2 個參數(shù)的信息
2、通過 request.getMultiFileMap()獲取文件類型的參數(shù),即可以獲取表單中 file1 和 file2 這 2 個文件的信息
稍后關(guān)注控制臺的輸出
/**
* 使用MultipartHttpServletRequest處理多文件上傳
* 上傳文件的http請求會被轉(zhuǎn)換為MultipartHttpServletRequest類型
* MultipartHttpServletRequest中提供了很多很多方法用來獲取請求中的參數(shù)
*
* @param request
* @return
*/
@RequestMapping("/upload3.do")
public ModelAndView upload3(MultipartHttpServletRequest request) {
//1.獲取表單中非文件數(shù)據(jù)
System.out.println("---------獲取表單中非文件數(shù)據(jù)---------");
Map parameterMap = request.getParameterMap();
parameterMap.forEach((name, values) -> {
System.out.println(String.format("%s:%s", name, Arrays.asList(values)));
});
//2、獲取表單中文件數(shù)據(jù)
System.out.println("---------獲取表單中文件數(shù)據(jù)---------");
MultiValueMap multiFileMap = request.getMultiFileMap();
//2、遍歷表單中元素信息
multiFileMap.forEach((name, files) -> {
System.out.println(String.format("%s:%s", name, files));
});
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/WEB-INF/view/result.jsp");
modelAndView.addObject("msg", "上傳成功");
return modelAndView;
}
使用 http client 發(fā)起請求
這里我們使用 idea 中的 http client 這個插件來調(diào)用接口,http client 插件是一個非常方便發(fā)起 http 請求額一個插件,測試接口特別容易,后面的大量案例中我們都會使用這個工具來快速測試接口的效果,所以這個工具,如果還不會的,建議去看一下這篇文章:
idea 中的接口測試?yán)鳎╤ttp cient 插件)
下面,我們在 idea 中創(chuàng)建一個 UploadController.http 文件,文件內(nèi)容如下:
### 多文件上傳
POST http://localhost:8080/chat04/upload3.do
Content-Type: multipart/form-data; boundary=bound1
--bound1
Content-Disposition: form-data; name="name"
路人
--bound1
Content-Disposition: form-data; name="age"
30
--bound1
Content-Disposition: form-data; name="file1"; filename="1.jpg"
< ./1.jpg
--bound1
Content-Disposition: form-data; name="file2"; filename="2.jpg"
Content-Type: image/jpeg
< ./2.jpg
--bound1--

控制臺輸出
---------獲取表單中非文件數(shù)據(jù)---------
name:[路人]
age:[30]
---------獲取表單中文件數(shù)據(jù)---------
file1:[MultipartFile[field="file1", filename=1.jpg, contentType=*/*; charset=UTF-8, size=145615]]
file2:[MultipartFile[field="file2", filename=2.jpg, contentType=image/jpeg, size=67713]]
9、自定義對象接收多文件上傳
表單代碼
這個表單用來輸入用戶信息:
姓名、年齡、頭像圖片、2 張身份證圖片
<form method="post" action="upload4.do" enctype="multipart/form-data">
姓名:<input name="name" value="路人"/> <br/>
年齡:<input name="age" value="30"/><br/>
頭像圖片:<input name="headImg" type="file"/><br/>
多張身份證圖片<br/>
<input name="idCardImg" type="file"/><br/>
<input name="idCardImg" type="file"/><br/>
<input type="submit" value="提交">
</form>
自定義一個類
自定義了一個 UserDto,來接收上面表單的參數(shù)。
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
public class UserDto {
//姓名
private String name;
//年齡
private Integer age;
//頭像
private MultipartFile headImg;
//身份證(多張圖像)
private List idCardImg;
//省略了get、set方法...
}
控制器代碼
@RequestMapping("/upload4.do")
public ModelAndView upload4(UserDto userDto) {
System.out.println("姓名:" + userDto.getName());
System.out.println("年齡:" + userDto.getAge());
System.out.println("頭像文件:" + userDto.getHeadImg());
System.out.println("多張身份證文件:" + Arrays.asList(userDto.getIdCardImg()));
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/WEB-INF/view/result.jsp");
modelAndView.addObject("msg", "上傳成功");
return modelAndView;
}
測試代碼
這里我們還是使用 http client 插件發(fā)起請求
### 多文件上傳
POST http://localhost:8080/chat04/upload4.do
Content-Type: multipart/form-data; boundary=bound1
--bound1
Content-Disposition: form-data; name="name"
Content-Type: text/plain
路人
--bound1
Content-Disposition: form-data; name="age"
Content-Type: text/plain
30
--bound1
Content-Disposition: form-data; name="headImg"; filename="1.jpg"
< ./1.jpg
--bound1
Content-Disposition: form-data; name="idCardImg"; filename="2.jpg"
Content-Type: image/jpeg
< ./2.jpg
--bound1
Content-Disposition: form-data; name="idCardImg"; filename="3.jpg"
Content-Type: image/jpeg
< ./3.jpg
--bound1--
控制臺輸出
輸出如下,可以看到 UserDto 這個對象中的詳細(xì)信息
姓名:路人
年齡:30
頭像文件:MultipartFile[field="headImg", filename=1.jpg, contentType=*/*; charset=UTF-8, size=145615]
多張身份證文件:[[MultipartFile[field="idCardImg", filename=2.jpg, contentType=image/jpeg, size=67713], MultipartFile[field="idCardImg", filename=3.jpg, contentType=image/jpeg, size=39891]]]12、擴(kuò)展
MultipartResolver 這個 bean 的名稱為什么必須是 multipartResolver?
springmvc 中會使用 MultipartResolver 來解析上傳文件的請求,具體代碼在org.springframework.web.servlet.DispatcherServlet#doDispatch中

進(jìn)入checkMultipart,如下,這里面關(guān)鍵代碼就是會調(diào)用this.multipartResolver.resolveMultipart(request)來處理文件上傳的請求

下面看一下 this.multipartResolver 從哪里來的,如下,是從 springmvc 容器中查找的,名稱為multipartResolver,所以我們定義這個 bean 的時候,名稱必須為這個。

13、案例代碼如何運(yùn)行?
step1:拉取代碼
https://gitee.com/javacode2018/springmvc-series
step2:導(dǎo)入 idea

step3:代碼結(jié)構(gòu)
本文的案例在chat04-uploadfile模塊中。
頁面
本文的表單代碼都在 index.jsp 中

控制器
本文的控制器代碼都在 UploadController 類中,如下

http client 測試案例代碼
如下圖,http client 測試案例代碼都在 UploadController.http 文件中,包含了 4 個案例的測試代碼,大家可以點(diǎn)擊之后直接運(yùn)行。

step4:下載 tomcat
鏈接:https://pan.baidu.com/s/1_Ol-UZkN_6woMBtjcFygvQ
提取碼:e66j
step5:將 chat04-uploadfile 部署到 tomcat


step6:啟動 tomcat,驗(yàn)證效果

14、SpringMVC 系列
SpringMVC 系列第 1 篇:helloword SpringMVC 系列第 2 篇:@Controller、@RequestMapping SpringMVC 系列第 3 篇:異常高效的一款接口測試?yán)?/a> SpringMVC 系列第 4 篇:controller 常見的接收參數(shù)的方式 SpringMVC 系列第 5 篇:@RequestBody 大解密,說點(diǎn)你不知道的
15、更多好文章
Spring 高手系列(共 56 篇) Java 高并發(fā)系列(共 34 篇) MySql 高手系列(共 27 篇) Maven 高手系列(共 10 篇) Mybatis 系列(共 12 篇) 聊聊 db 和緩存一致性常見的實(shí)現(xiàn)方式 接口冪等性這么重要,它是什么?怎么實(shí)現(xiàn)? 泛型,有點(diǎn)難度,會讓很多人懵逼,那是因?yàn)槟銢]有看這篇文章!
16、推薦一個高質(zhì)量的公眾號
大家平時在學(xué)習(xí)技術(shù)的過程中,苦于找不到高質(zhì)量的學(xué)習(xí)資料的,可以關(guān)注一下【Java 充電社】,這個號專注于為大家提供高質(zhì)量的學(xué)習(xí)資源,已發(fā)布了大量高質(zhì)量的學(xué)習(xí)視頻、及資源,大家可以關(guān)注下。
