一、简介

在本教程中,我们将重点介绍在 Spring Boot 中发送多部分请求的各种机制。多部分请求包括发送由边界分隔的各种不同类型的数据,作为单个 HTTP 方法调用的一部分。

一般来说,我们可以在此请求中发送复杂的 JSON、XML 或 CSV 数据以及传输多部分文件。多部分文件的示例可以是音频或图像文件。同样,我们还可以将简单的键/值对数据与多部分文件一起作为多部分请求发送。

让我们研究一下发送这些数据的各种方式。

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

最后,我们将创建一个接受表单数据的方法,包括多部分文件:

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

这里,两个特别重要的细节是:

  • Consumers 属性值设置为 multipart/form-data
  • @ModelAttribute 已将所有表单数据捕获Employee POJO 中,包括上传的文件

3.使用 @RequestPart

此注释 将多部分请求的一部分与方法参数相关联, 这对于将复杂的多属性数据作为有效负载(例如 JSON 或 XML)发送非常有用。

让我们创建一个带有两个参数的方法,第一个参数为 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 部分的内容类型设置为 application/JSON 。此外,除了多部分文件之外,我们还以 JSON 文件的形式发送此数据。

有关如何测试多部分请求的更多详细信息可以在此处找到。

4.使用 @RequestParam

发送多部分数据的另一种方法是使用 @RequestParam 。这 对于简单数据特别有用,这些数据作为键/值对与文件一起发送

@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 中有效处理多部分请求。

最初,我们使用模型属性发送多部分表单数据。然后我们研究了如何使用 @RequestPart@RequestParam 注解单独接收多部分数据。

与往常一样,完整的源代码可以在 GitHub 上获取。