# Spring REST Multipart – 多部分上传示例

> 原文： [https://howtodoinjava.com/spring-restful/multipart-multiple-uploads-example/](https://howtodoinjava.com/spring-restful/multipart-multiple-uploads-example/)

了解如何使用 Spring REST API 接受**上传多个多部分**二进制文件（例如 jpeg 图像），这些文件接受[`MultipartFile`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/multipart/MultipartFile.html)请求的数组。

## 1\. Maven 依赖

除了 [spring webmvc](https://howtodoinjava.com/spring-mvc-tutorial/) 之外，我们还将在类路径中需要[`commons-fileupload`](https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload)和[`commons-io`](https://mvnrepository.com/artifact/commons-io/commons-io)。

`pom.xml`

```java
dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
	<version>5.1.6.RELEASE</version>
</dependency>

<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\. 配置`CommonsMultipartResolver`

它是`commons-fileupload`的基于 Servlet 的[`MultipartResolver`](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/multipart/commons/CommonsMultipartResolver.html)实现。 它提供`maxUploadSize`，`maxInMemorySize`和`defaultEncoding`设置作为 bean 属性。

此类的目的是将临时文件保存到 [Servlet](https://howtodoinjava.com/servlets/complete-java-servlets-tutorial/) 容器的临时目录中。

`rest-servlet.xml`

```java
<beans>
	...
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<property name="maxUploadSize" value="1000000"/>
	</bean>
	...
</beans>

```

等效的 Java 注解配置为：

```java
@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver()
{
    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    multipartResolver.setMaxUploadSize(20848820);
    return multipartResolver;
}

```

## 3\. 创建多部分上载 Rest API

创建给定的 [REST API](http://restfulapi.net/) ，该 API 将负责处理发布到服务器的多个上载。 在给出的示例中，我在路径`/employee-management/employees/1/photo/multiple`处创建了 API。

我假设 ID 为`'1'`的员工存在于数据库中。 随时更改资源路径和实现。

`EmployeeImageController.java`

```java
package com.howtodoinjava.demo.controller;

import static org.springframework.web.servlet
		.support.ServletUriComponentsBuilder.fromCurrentRequest;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.concurrent.Callable;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.howtodoinjava.demo.exception.RecordNotFoundException;
import com.howtodoinjava.demo.model.Employee;
import com.howtodoinjava.demo.repository.EmployeeRepository;

@RestController
@RequestMapping(value = "/employee-management/employees/{id}/photo")
@PropertySource("classpath:application.properties")
public class EmployeeImageController {

	@Autowired
	private EmployeeRepository repository;

	private File uploadDirRoot;

	@Autowired
	EmployeeImageController(@Value("${image.upload.dir}") String uploadDir, 
										EmployeeRepository repository) {
		this.uploadDirRoot = new File(uploadDir);
		this.repository = repository;
	}

	@PostMapping(value = "/multiple", consumes = { "multipart/form-data" })
	Callable<ResponseEntity<?>> writeMultiple(@PathVariable Long id, 
					@RequestParam("files") MultipartFile[] files) throws Exception 
	{
		return () -> this.repository.findById(id).map(employee ->
		{

			Arrays.asList(files).stream().forEach(file -> 
			{
				File fileForEmployee;

				try {
					fileForEmployee = uploadPath(employee, file);
				} catch (IOException e) {
					throw new RuntimeException(e);
				}

				try (InputStream in = file.getInputStream(); OutputStream out = new FileOutputStream(fileForEmployee)) {
					FileCopyUtils.copy(in, out);
				} catch (IOException ex) {
					throw new RuntimeException(ex);
				}
			});

			return ResponseEntity.ok().build();
		}).orElseThrow(() -> new RecordNotFoundException("Employee id is not present in database"));
	}

	private File uploadPath(Employee e, MultipartFile file) throws IOException 
	{
		File uploadPath = Paths.get(this.uploadDirRoot.getPath(), e.getId().toString()).toFile();
		if(uploadPath.exists() == false) {
			uploadPath.mkdirs();
		}
		return new File(uploadPath.getAbsolutePath(), file.getOriginalFilename());
	}
}

```

如果文件系统中尚不存在上述 REST 控制器，则会创建一个上载文件夹（名称为员工 ID）。 仍然需要定义以下属性。

`application.properties`

```java
image.upload.dir=c:/temp/images

```

同样，控制器返回可调用的 **[](https://howtodoinjava.com/java/multi-threading/java-callable-future-example/)**，这意味着该方法将在 IO 操作可能运行时立即返回。 上传过程完成后，API 将返回响应。 要**启用异步支持**，请在[`DispatcherServlet`](https://howtodoinjava.com/spring5/webmvc/spring-dispatcherservlet-tutorial/)中配置**异步支持的**。

`web.xml`

```java
<web-app>
	<display-name>Employee Management REST APIs</display-name>

	<servlet>
		<servlet-name>rest</servlet-name> 
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
		<async-supported>true</async-supported>
	</servlet>

	<servlet-mapping>
		<servlet-name>rest</servlet-name>
		<url-pattern>/api/rest/*</url-pattern>
	</servlet-mapping>

</web-app>

```

## 4\. 多部分上传请求演示

出于演示目的，我创建了一个 JSP 页面，其中仅包含文件类型的多个字段。 我们将从计算机浏览一些图像，并将其上传到服务器。

`multipleFileUpload.jsp`

```java
<html>
<head>
<title>Spring REST File Upload</title>
</head>
<body>
	<form method="POST" action="/SpringRestExample/api/rest/employee-management/employees/1/photo/multiple"
		enctype="multipart/form-data">
		<table>
			<tr>
				<td>Select first file to upload</td>
				<td><input type="file" name="files" /></td>
			</tr>
			<tr>
				<td>Select second file to upload</td>
				<td><input type="file" name="files" /></td>
			</tr>
			<tr>
				<td>Select third file to upload</td>
				<td><input type="file" name="files" /></td>
			</tr>
			<tr>
				<td><input type="submit" value="Submit" /></td>
			</tr>
		</table>
	</form>
</body>
</html>

```

现在启动服务器并在 URL `http://localhost:8080/SpringRestExample/multipleFileUpload.jsp`中打开上传页面。 浏览图像，然后单击提交按钮。 图像文件将被上传到配置的上传目录中的服务器。

要下载文件，请在浏览器中输入 URL `/employee-management/employees/1/photo`，然后将显示图像。 下载 API 已包含在附件中。

请问您有关创建 **Spring MVC REST API 来处理文件（例如图像）的多个**上传问题。

[下载源码](https://howtodoinjava.com/wp-content/downloads/SpringRestMultiPartExample.zip)

学习愉快！