Multipart Request Handling in Spring – Spring中的多部分请求处理

最后修改: 2021年 5月 20日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.绪论

In this tutorial, we’ll focus on various mechanisms for sending multipart requests in Spring Boot. Multipart requests consist of sending data of many different types separated by a boundary as part of a single HTTP method call.

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

Generally, we can send complicated JSON, XML, or CSV data, as well as transfer multipart file(s) in this request. Examples of multipart files include audio or image files. Furthermore, we can send simple key/value pair data with the multipart file(s) as a multipart request.

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

Now let’s look into the various ways we can send this data.

现在让我们来看看我们可以通过哪些方式来发送这些数据。

2. Using @ModelAttribute

2.使用@ModelAttribute

Let’s consider a simple use case of sending an employee’s data consisting of a name and file using a form.

让我们考虑一个简单的用例,即用一个表单发送一个由姓名和文件组成的雇员数据。

First, we’ll create an Employee abstraction to store the form data:

首先,我们将创建一个Employee抽象来存储表单数据。

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

Then we’ll generate the form using Thymeleaf:

然后我们将使用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>

The important thing to note is that we declare the enctype as multipart/form-data in the view.

需要注意的是,我们在视图中声明enctypemultipart/form-data

Finally, we’ll create a method that accepts the form data, including the multipart file:

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

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

Here, the two particularly important details are:

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

  • consumes attribute value is set to multipart/form-data
  • @ModelAttribute has captured all the form data into the Employee POJO, including the uploaded file

3. Using @RequestPart

3.使用@RequestPart

This annotation associates a part of a multipart request with the method argument, which is useful for sending complex multi-attribute data as payload, e.g., JSON or XML.

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

Let’s create a method with two arguments, first of type Employee and second as MultipartFile. Furthermore, we’ll annotate both of these arguments with @RequestPart:

让我们创建一个有两个参数的方法,第一个是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();
}

Now, to see this annotation in action, we’ll create the test using MockMultipartFile:

现在,为了看到这个注解的作用,我们将使用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());
}

The important thing to note above is that we’ve set the content type of the Employee part as application/JSON. We’re also sending this data as a JSON file in addition to the multipart file.

上面需要注意的是,我们已经将Employee部分的内容类型设置为application/JSON。除了多部分文件之外,我们还将这些数据作为JSON文件发送。

Further details on how to test multipart requests can be found here.

关于如何测试多部分请求的进一步细节,可以在这里找到。

4. Using @RequestParam

4.使用@RequestParam

Another way of sending multipart data is to use @RequestParam. This is especially useful for simple data, which is sent as key/value pairs along with the file:

发送多部分数据的另一种方法是使用@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();
}

Let’s write the test for this method to demonstrate:

我们来写一下这个方法的测试,以示证明。

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

5. Conclusion

5.总结

In this article, we learned how to effectively handle multipart requests in Spring Boot.

在这篇文章中,我们学习了如何在Spring Boot中有效处理多部分请求。

Initially, we sent multipart form data using a model attribute. Then we looked at how to separately receive multipart data using the @RequestPart and @RequestParam annotations.

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

As always, the full source code is available over on GitHub.

一如既往,完整的源代码可在GitHub上获得