1、本文内容

  • 文件上传开发步骤
  • 单文件上传
  • 多文件上传
  • 通过 MultipartHttpServletRequest 处理文件上传
  • 通过自定义对象接收上传的文件
  • 扩展知识
  • 案例代码

2、预备知识

springmvc 系列中的测试案例,基本上都是使用 idea 中的 http client 插件开发的,是一款非常高效的接口测试工具,还没有用过的,建议先去了解下用法:idea 中的接口测试利器(http 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、调用 MultipartFile#transferTo 方法保存文件
5、指定请求类型为:multipart/form-data

步骤 1:添加 maven 配置

    commons-fileupload    commons-fileupload    1.4    commons-io    commons-io    2.6

步骤 2:定义 MultipartResolver 这个 bean

           

http 上传的请求类型为 multipart/form-data 类型,springmvc 内部需要为这种请求指定解析器,解析器的类型为org.springframework.web.multipart.MultipartResolver
MultipartResolver 有 2 个实现类,这里我们使用 CommonsMultipartResolver 作为解析器来解析文件上传的 http 请求
注意 bean 名称必须为multipartResolver
两个比较有用的属性
maxUploadSizePerFile:单个文件大小限制(byte)
maxUploadSize:整个请求大小限制(byte)

步骤 3:控制器使用 MultipartFile 接收上传的文件

@RequestMapping("/upload1.do")public ModelAndView upload1(@RequestParam("file1") MultipartFile f1){}

步骤 4:调用 MultipartFile#transferTo 方法保存文件

@RequestMapping("/upload1.do")public ModelAndView upload1(@RequestParam("file1") MultipartFile f1){ //destFile为目标文件,即将上传的文件写到destFile中 f1.transferTo(destFile);}

步骤 5:设置 http 请求类型为 multipart/form-data

上传文件,需要设置 form 表单的 enctype 属性值为 multipart/form-data

文件:

表单中文件元素的 name 为 file1

控制器代码

/** * 单文件上传 * 1、MultipartFile用来接收表单中上传的文件 * 2、每个MultipartFile对应表单中的一个元素 * 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);    //调用transferTo将上传的文件保存到指定的地址    f1.transferTo(destFile);    ModelAndView modelAndView = new ModelAndView();    modelAndView.setViewName("/WEB-INF/view/result.jsp");    modelAndView.addObject("msg", destFile.getAbsolutePath());    return modelAndView;}

上传的文件会被传入 update1 方法的第一个参数,注意第一个参数有个@RequestParam(“file1”)注解,这个注解的 value 就是表单中文件元素名称。

7、多文件上传

当上传多个文件的时候,可以使用多个 MultipartFile 参数来接收上传的文件。

表单代码

    文件1:
文件2:

控制器代码

/** * 多文件上传 * 1、方法中指定多个MultipartFile,每个MultipartFile对应一个上传的文件 * 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 接受到上传文件的的请求之后,会将请求转换为 MultipartHttpServletRequest 类型的对象
2、MultipartHttpServletRequest 中提供了一系列方法来获取请求中的所有参数信息
3、其中 getParameterMap()用来获取非文件类型的参数列表
4、getMultiFileMap()方法用来获取上传的文件列表

姓名:
年龄:
文件1:
文件2:

控制器代码

控制器中使用 MultipartHttpServletRequest 来获取所有参数信息,分了 2 部分获取
1、先使用 request.getParameterMap()获取非文件类型的参数,即可以获取表单中的 name 和 age 这 2 个参数的信息
2、通过 request.getMultiFileMap()获取文件类型的参数,即可以获取表单中 file1 和 file2 这 2 个文件的信息
稍后关注控制台的输出

/** * 使用MultipartHttpServletRequest处理多文件上传 * 上传文件的http请求会被转换为MultipartHttpServletRequest类型 * MultipartHttpServletRequest中提供了很多很多方法用来获取请求中的参数 * * @param request * @return */@RequestMapping("/upload3.do")public ModelAndView upload3(MultipartHttpServletRequest request) {    //1.获取表单中非文件数据    System.out.println("---------获取表单中非文件数据---------");    Map parameterMap = request.getParameterMap();    parameterMap.forEach((name, values) -> {        System.out.println(String.format("%s:%s", name, Arrays.asList(values)));    });    //2、获取表单中文件数据    System.out.println("---------获取表单中文件数据---------");    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 发起请求

这里我们使用 idea 中的 http client 这个插件来调用接口,http client 插件是一个非常方便发起 http 请求额一个插件,测试接口特别容易,后面的大量案例中我们都会使用这个工具来快速测试接口的效果,所以这个工具,如果还不会的,建议去看一下这篇文章:

idea 中的接口测试利器(http cient 插件)

下面,我们在 idea 中创建一个 UploadController.http 文件,文件内容如下:

### 多文件上传POST http://localhost:8080/chat04/upload3.doContent-Type: multipart/form-data; boundary=bound1--bound1Content-Disposition: form-data; name="name"路人--bound1Content-Disposition: form-data; name="age"30--bound1Content-Disposition: form-data; name="file1"; filename="1.jpg"< ./1.jpg--bound1Content-Disposition: form-data; name="file2"; filename="2.jpg"Content-Type: image/jpeg< ./2.jpg--bound1--

姓名:
年龄:
头像图片:
多张身份证图片

自定义一个类

自定义了一个 UserDto,来接收上面表单的参数。

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 插件发起请求

### 多文件上传POST http://localhost:8080/chat04/upload4.doContent-Type: multipart/form-data; boundary=bound1--bound1Content-Disposition: form-data; name="name"Content-Type: text/plain路人--bound1Content-Disposition: form-data; name="age"Content-Type: text/plain30--bound1Content-Disposition: form-data; name="headImg"; filename="1.jpg"< ./1.jpg--bound1Content-Disposition: form-data; name="idCardImg"; filename="2.jpg"Content-Type: image/jpeg< ./2.jpg--bound1Content-Disposition: form-data; name="idCardImg"; filename="3.jpg"Content-Type: image/jpeg< ./3.jpg--bound1--

控制台输出

输出如下,可以看到 UserDto 这个对象中的详细信息

姓名:路人年龄: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、扩展

MultipartResolver 这个 bean 的名称为什么必须是 multipartResolver?

springmvc 中会使用 MultipartResolver 来解析上传文件的请求,具体代码在org.springframework.web.servlet.DispatcherServlet#doDispatch中

下面看一下 this.multipartResolver 从哪里来的,如下,是从 springmvc 容器中查找的,名称为multipartResolver,所以我们定义这个 bean 的时候,名称必须为这个。

step3:代码结构

本文的案例在chat04-uploadfile模块中。

页面

本文的表单代码都在 index.jsp 中

http client 测试案例代码

如下图,http client 测试案例代码都在 UploadController.http 文件中,包含了 4 个案例的测试代码,大家可以点击之后直接运行。

14、SpringMVC 系列

  1. SpringMVC 系列第 1 篇:helloword
  2. SpringMVC 系列第 2 篇:@Controller、@RequestMapping
  3. SpringMVC 系列第 3 篇:异常高效的一款接口测试利器
  4. SpringMVC 系列第 4 篇:controller 常见的接收参数的方式
  5. SpringMVC 系列第 5 篇:@RequestBody 大解密,说点你不知道的

15、更多好文章

  1. Spring 高手系列(共 56 篇)
  2. Java 高并发系列(共 34 篇)
  3. MySql 高手系列(共 27 篇)
  4. Maven 高手系列(共 10 篇)
  5. Mybatis 系列(共 12 篇)
  6. 聊聊 db 和缓存一致性常见的实现方式
  7. 接口幂等性这么重要,它是什么?怎么实现?
  8. 泛型,有点难度,会让很多人懵逼,那是因为你没有看这篇文章!

各位小伙伴,如果本文对你有帮助,不要光看,记得点赞加关注,这对我来说,非常非常重要,也是我继续做下去的一个动力。