Spring Boot 处理 Multipart 文件上传请求

1、简介

本文将带你了解如何在 Spring Boot 项目中处理 Multipart 文件上传请求。

Multipart 请求可以包含多个独立的请求体部分,通常用于文件上传。除了文件以外,还可以同时上传表单、JSON、XML 等等数据。

2、使用 @ModelAttribute

一个简单的示例,使用表单发送包含了员工姓名和文件的数据。

创建 Employee 类:

public class Employee {
    private String name;
    private MultipartFile document;
}

然后,使用 Thymeleaf 渲染表单:

<form action="#" th:action="@{/employee}" th:object="${employee}" method="post" enctype="multipart/form-data">
    <p>name: <input type="text" th:field="*{name}" /></p>
    <p>document:<input type="file" th:field="*{document}" multiple="multiple"/>
    <input type="submit" value="upload" />
    <input type="reset" value="Reset" /></p>
</form>

注意,需要将表单的 enctype 属性声明为 multipart/form-data

最后,创建一个接受表单数据(包括 Multipart 文件)的方法:

@RequestMapping(path = "/employee", method = POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
public String saveEmployee(@ModelAttribute Employee employee) {
    employeeService.save(employee);
    return "employee/success";
}

这里有两个细节:

  • consumes 属性值设置为 multipart/form-data
  • @ModelAttribute 将所有表单数据封装到 Employee POJO 中,包括上传的文件。

3、使用 @RequestPart

该注解将 Multipart 请求的一部分(Part)封装到方法参数,这对于发送复杂的 Multipart 数据(如 JSON 或 XML)作为 Payload 时非常有用。

创建一个包含两个参数的方法,第一个参数为 Employee 类型,第二个参数为 MultipartFile 类型。另外,还用 @RequestPart 对这两个参数进行注解:

@RequestMapping(path = "/requestpart/employee", method = POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
public ResponseEntity<Object> saveEmployee(@RequestPart Employee employee, @RequestPart MultipartFile document) {
    employee.setDocument(document);
    employeeService.save(employee);
    return ResponseEntity.ok().build();
}

现在,使用 MockMultipartFile 创建一个测试,以查看此注解的实际效果:

@Test
public void givenEmployeeJsonAndMultipartFile_whenPostWithRequestPart_thenReturnsOK() throws Exception {
    MockMultipartFile employeeJson = new MockMultipartFile("employee", null,
      "application/json", "{\"name\": \"Emp Name\"}".getBytes());

    mockMvc.perform(multipart("/requestpart/employee")
      .file(A_FILE)
      .file(employeeJson))
      .andExpect(status().isOk());
}

需要注意的是,将 Employee Part 的 Content Type 设置为了 application/json。除了 Multipart 文件外,还将以 JSON 文件的形式发送此数据。

@RequestPart 注解会根据 Part 的 Content Type 解析数据。

4、使用 @RequestParam

接收 Multipart 数据的另一种方法是使用 @RequestParam。这对于简单数据尤其有用,即 Multipart 请求中的那些 Key/Value 表单数据。

@RequestMapping(path = "/requestparam/employee", method = POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE })
public ResponseEntity<Object> saveEmployee(@RequestParam String name, @RequestPart MultipartFile document) {
    Employee employee = new Employee(name, document);
    employeeService.save(employee);
    return ResponseEntity.ok().build();
}

测试:

@Test
public void givenRequestPartAndRequestParam_whenPost_thenReturns200OK() throws Exception {
    mockMvc.perform(multipart("/requestparam/employee")
      .file(A_FILE)
      .param("name", "testname"))
      .andExpect(status().isOk());
}

5、总结

本文介绍了如何在 Spring Boot 中使用 @ModelAttribute、@RequestPart 或 @RequestParam 来处理 Multipart 文件上传请求。


Ref:https://www.baeldung.com/sprint-boot-multipart-requests